@@ -32,6 +32,8 @@ import {
3232} from "./parser" ;
3333import { OwlError } from "../common/owl_error" ;
3434
35+ const zero = Symbol ( "" ) ;
36+
3537type BlockType = "block" | "text" | "multi" | "list" | "html" | "comment" ;
3638const whitespaceRE = / \s + / g;
3739
@@ -279,7 +281,7 @@ export class CodeGenerator {
279281 translatableAttributes : string [ ] = TRANSLATABLE_ATTRS ;
280282 ast : AST ;
281283 staticDefs : { id : string ; expr : string } [ ] = [ ] ;
282- slotNames : Set < String > = new Set ( ) ;
284+ slotNames : Set < String | Symbol > = new Set ( ) ;
283285 helpers : Set < string > = new Set ( ) ;
284286
285287 constructor ( ast : AST , options : CodeGenOptions ) {
@@ -791,12 +793,24 @@ export class CodeGenerator {
791793 return block ! . varName ;
792794 }
793795
796+ compileZero ( ) {
797+ this . helpers . add ( "zero" ) ;
798+ this . helpers . add ( "zero2" ) ;
799+ this . helpers . add ( "callLazyBlock" ) ;
800+ const isMultiple = this . slotNames . has ( zero ) ;
801+ this . slotNames . add ( zero ) ;
802+ let key = this . target . loopLevel ? `key${ this . target . loopLevel } ` : "key" ;
803+ if ( isMultiple ) {
804+ key = this . generateComponentKey ( key ) ;
805+ }
806+ return `zero2 in ctx ? callLazyBlock(ctx[zero2], node, ${ key } ) : ctx[zero]` ;
807+ }
808+
794809 compileTEsc ( ast : ASTTEsc , ctx : Context ) : string {
795810 let { block, forceNewBlock } = ctx ;
796811 let expr : string ;
797812 if ( ast . expr === "0" ) {
798- this . helpers . add ( "zero" ) ;
799- expr = `ctx[zero]` ;
813+ expr = this . compileZero ( ) ;
800814 } else {
801815 expr = compileExpr ( ast . expr ) ;
802816 if ( ast . defaultValue ) {
@@ -824,8 +838,7 @@ export class CodeGenerator {
824838 block = this . createBlock ( block , "html" , ctx ) ;
825839 let blockStr ;
826840 if ( ast . expr === "0" ) {
827- this . helpers . add ( "zero" ) ;
828- blockStr = `ctx[zero]` ;
841+ blockStr = this . compileZero ( ) ;
829842 } else if ( ast . body ) {
830843 let bodyValue = null ;
831844 bodyValue = BlockDescription . nextBlockId ;
@@ -1044,50 +1057,73 @@ export class CodeGenerator {
10441057
10451058 compileTCall ( ast : ASTTCall , ctx : Context ) : string {
10461059 let { block, forceNewBlock } = ctx ;
1060+
1061+ const attrs : string [ ] = ast . attrs
1062+ ? this . formatPropObject ( ast . attrs , ast . attrsTranslationCtx , ctx . translationCtx )
1063+ : [ ] ;
10471064 let ctxVar = ctx . ctxVar || "ctx" ;
1048- if ( ast . context ) {
1065+ if ( ! ast . attrs && ast . context ) {
10491066 ctxVar = generateId ( "ctx" ) ;
10501067 this . addLine ( `let ${ ctxVar } = ${ compileExpr ( ast . context ) } ;` ) ;
10511068 }
1069+
10521070 const isDynamic = INTERP_REGEXP . test ( ast . name ) ;
10531071 const subTemplate = isDynamic ? interpolate ( ast . name ) : "`" + ast . name + "`" ;
10541072 if ( block && ! forceNewBlock ) {
10551073 this . insertAnchor ( block ) ;
10561074 }
10571075 block = this . createBlock ( block , "multi" , ctx ) ;
10581076 if ( ast . body ) {
1059- this . addLine ( `${ ctxVar } = Object.create(${ ctxVar } );` ) ;
1060- this . addLine ( `${ ctxVar } [isBoundary] = 1;` ) ;
1061- this . helpers . add ( "isBoundary" ) ;
1062- const subCtx = createContext ( ctx , { ctxVar } ) ;
1063- const bl = this . compileMulti ( { type : ASTType . Multi , content : ast . body } , subCtx ) ;
1064- if ( bl ) {
1065- this . helpers . add ( "zero" ) ;
1066- this . addLine ( `${ ctxVar } [zero] = ${ bl } ;` ) ;
1077+ if ( ast . attrs ) {
1078+ let ctxStr = "ctx" ;
1079+ if ( this . target . loopLevel || ! this . hasSafeContext ) {
1080+ ctxStr = generateId ( "ctx" ) ;
1081+ this . helpers . add ( "capture" ) ;
1082+ this . define ( ctxStr , `capture(ctx)` ) ;
1083+ }
1084+ const name = this . compileInNewTarget ( "callBody" , ast . body , ctx ) ;
1085+ this . helpers . add ( "zero2" ) ;
1086+ attrs . push ( `[zero2]: {__render: ${ name } .bind(this), __ctx: ${ ctxStr } }` ) ;
1087+ } else {
1088+ this . addLine ( `${ ctxVar } = Object.create(${ ctxVar } );` ) ;
1089+ this . addLine ( `${ ctxVar } [isBoundary] = 1;` ) ;
1090+ this . helpers . add ( "isBoundary" ) ;
1091+ const subCtx = createContext ( ctx , { ctxVar } ) ;
1092+ const bl = this . compileAST ( ast . body , subCtx ) ;
1093+ if ( bl ) {
1094+ this . helpers . add ( "zero" ) ;
1095+ this . addLine ( `${ ctxVar } [zero] = ${ bl } ;` ) ;
1096+ }
10671097 }
10681098 }
1069-
1099+ let ctxString = `{${ attrs . join ( ", " ) } }` ;
1100+ if ( ast . attrs && ast . context ) {
1101+ const dynCtxVar = generateId ( "ctx" ) ;
1102+ this . addLine ( `let ${ dynCtxVar } = ${ compileExpr ( ast . context ) } ;` ) ;
1103+ ctxString = `Object.assign({}, ${ dynCtxVar } ${ attrs . length ? ", " + ctxString : "" } )` ;
1104+ }
1105+ const ctxExpr = ast . attrs ? ctxString : ctxVar ;
10701106 const key = this . generateComponentKey ( ) ;
10711107 if ( isDynamic ) {
10721108 const templateVar = generateId ( "template" ) ;
10731109 if ( ! this . staticDefs . find ( ( d ) => d . id === "call" ) ) {
10741110 this . staticDefs . push ( { id : "call" , expr : `app.callTemplate.bind(app)` } ) ;
10751111 }
10761112 this . define ( templateVar , subTemplate ) ;
1077- this . insertBlock ( `call(this, ${ templateVar } , ${ ctxVar } , node, ${ key } )` , block ! , {
1113+ this . insertBlock ( `call(this, ${ templateVar } , ${ ctxExpr } , node, ${ key } )` , block ! , {
10781114 ...ctx ,
10791115 forceNewBlock : ! block ,
10801116 } ) ;
10811117 } else {
10821118 const id = generateId ( `callTemplate_` ) ;
10831119 this . staticDefs . push ( { id, expr : `app.getTemplate(${ subTemplate } )` } ) ;
1084- this . insertBlock ( `${ id } .call(this, ${ ctxVar } , node, ${ key } )` , block ! , {
1120+ this . insertBlock ( `${ id } .call(this, ${ ctxExpr } , node, ${ key } )` , block ! , {
10851121 ...ctx ,
10861122 forceNewBlock : ! block ,
10871123 } ) ;
10881124 }
1089- if ( ast . body && ! ctx . isLast ) {
1090- this . addLine ( `${ ctxVar } = ${ ctxVar } .__proto__;` ) ;
1125+ if ( ! ast . attrs && ast . body && ! ctx . isLast ) {
1126+ this . addLine ( `${ ctxExpr } = ${ ctxExpr } .__proto__;` ) ;
10911127 }
10921128 return block . varName ;
10931129 }
0 commit comments