@@ -355,170 +355,184 @@ public String render(Node root, boolean processExtendRoots) {
355355 * @return rendered result
356356 */
357357 private String render (Node root , boolean processExtendRoots , long renderLimit ) {
358- OutputList output = new OutputList (
359- RenderLimitUtils .clampProvidedRenderLimitToConfig (renderLimit , config )
360- );
361- for (Node node : root .getChildren ()) {
362- lineNumber = node .getLineNumber ();
363- position = node .getStartPosition ();
364- String renderStr = node .getMaster ().getImage ();
365- try {
366- if (node instanceof ExpressionNode && context .doesRenderStackContain (renderStr )) {
367- // This is a circular rendering. Stop rendering it here.
368- addError (
369- new TemplateError (
370- ErrorType .WARNING ,
371- ErrorReason .EXCEPTION ,
372- ErrorItem .TAG ,
373- "Rendering cycle detected: '" + renderStr + "'" ,
374- null ,
375- getLineNumber (),
376- node .getStartPosition (),
377- null ,
378- BasicTemplateErrorCategory .IMPORT_CYCLE_DETECTED ,
379- ImmutableMap .of ("string" , renderStr )
380- )
381- );
382- output .addNode (new RenderedOutputNode (renderStr ));
383- } else {
384- OutputNode out ;
385- try (
386- AutoCloseableImpl <String > closeable = context
387- .closeablePushRenderStack (renderStr )
388- .get ()
358+ boolean pushed = false ;
359+ //noinspection ErrorProne
360+ if (JinjavaInterpreter .getCurrent () != this ) {
361+ JinjavaInterpreter .pushCurrent (this );
362+ pushed = true ;
363+ }
364+ try {
365+ OutputList output = new OutputList (
366+ RenderLimitUtils .clampProvidedRenderLimitToConfig (renderLimit , config )
367+ );
368+ for (Node node : root .getChildren ()) {
369+ lineNumber = node .getLineNumber ();
370+ position = node .getStartPosition ();
371+ String renderStr = node .getMaster ().getImage ();
372+ try {
373+ if (
374+ node instanceof ExpressionNode && context .doesRenderStackContain (renderStr )
389375 ) {
390- try {
391- out = node .render (this );
392- } catch (DeferredValueException e ) {
393- context .handleDeferredNode (node );
394- out = new RenderedOutputNode (node .getMaster ().getImage ());
376+ // This is a circular rendering. Stop rendering it here.
377+ addError (
378+ new TemplateError (
379+ ErrorType .WARNING ,
380+ ErrorReason .EXCEPTION ,
381+ ErrorItem .TAG ,
382+ "Rendering cycle detected: '" + renderStr + "'" ,
383+ null ,
384+ getLineNumber (),
385+ node .getStartPosition (),
386+ null ,
387+ BasicTemplateErrorCategory .IMPORT_CYCLE_DETECTED ,
388+ ImmutableMap .of ("string" , renderStr )
389+ )
390+ );
391+ output .addNode (new RenderedOutputNode (renderStr ));
392+ } else {
393+ OutputNode out ;
394+ try (
395+ AutoCloseableImpl <String > closeable = context
396+ .closeablePushRenderStack (renderStr )
397+ .get ()
398+ ) {
399+ try {
400+ out = node .render (this );
401+ } catch (DeferredValueException e ) {
402+ context .handleDeferredNode (node );
403+ out = new RenderedOutputNode (node .getMaster ().getImage ());
404+ }
395405 }
406+ output .addNode (out );
396407 }
397- output .addNode (out );
398- }
399- } catch (OutputTooBigException e ) {
400- addError (TemplateError .fromOutputTooBigException (e ));
401- return output .getValue ();
402- } catch (CollectionTooBigException e ) {
403- addError (
404- new TemplateError (
405- ErrorType .FATAL ,
406- ErrorReason .COLLECTION_TOO_BIG ,
407- ErrorItem .OTHER ,
408- ExceptionUtils .getMessage (e ),
409- null ,
410- -1 ,
411- -1 ,
412- e ,
413- BasicTemplateErrorCategory .UNKNOWN ,
414- ImmutableMap .of ()
415- )
416- );
417- return output .getValue ();
418- }
419- }
420- DynamicRenderedOutputNode pathSetter = new DynamicRenderedOutputNode ();
421- output .addNode (pathSetter );
422- Optional <String > basePath = context .getCurrentPathStack ().peek ();
423- StringBuilder ignoredOutput = new StringBuilder ();
424- // render all extend parents, keeping the last as the root output
425- if (processExtendRoots ) {
426- Set <String > extendPaths = new HashSet <>();
427- Optional <String > extendPath = context .getExtendPathStack ().peek ();
428- int numDeferredTokensBefore = 0 ;
429- while (!extendParentRoots .isEmpty ()) {
430- if (extendPaths .contains (extendPath .orElse ("" ))) {
408+ } catch (OutputTooBigException e ) {
409+ addError (TemplateError .fromOutputTooBigException (e ));
410+ return output .getValue ();
411+ } catch (CollectionTooBigException e ) {
431412 addError (
432- TemplateError .fromException (
433- new ExtendsTagCycleException (
434- extendPath .orElse ("" ),
435- context .getExtendPathStack ().getTopLineNumber (),
436- context .getExtendPathStack ().getTopStartPosition ()
437- )
413+ new TemplateError (
414+ ErrorType .FATAL ,
415+ ErrorReason .COLLECTION_TOO_BIG ,
416+ ErrorItem .OTHER ,
417+ ExceptionUtils .getMessage (e ),
418+ null ,
419+ -1 ,
420+ -1 ,
421+ e ,
422+ BasicTemplateErrorCategory .UNKNOWN ,
423+ ImmutableMap .of ()
438424 )
439425 );
440- break ;
426+ return output . getValue () ;
441427 }
442- extendPaths .add (extendPath .orElse ("" ));
443- try (
444- AutoCloseableImpl <Result <String , TagCycleException >> closeableCurrentPath =
445- context
446- .getCurrentPathStack ()
447- .closeablePush (
448- extendPath .orElse ("" ),
449- context .getExtendPathStack ().getTopLineNumber (),
450- context .getExtendPathStack ().getTopStartPosition ()
428+ }
429+ DynamicRenderedOutputNode pathSetter = new DynamicRenderedOutputNode ();
430+ output .addNode (pathSetter );
431+ Optional <String > basePath = context .getCurrentPathStack ().peek ();
432+ StringBuilder ignoredOutput = new StringBuilder ();
433+ // render all extend parents, keeping the last as the root output
434+ if (processExtendRoots ) {
435+ Set <String > extendPaths = new HashSet <>();
436+ Optional <String > extendPath = context .getExtendPathStack ().peek ();
437+ int numDeferredTokensBefore = 0 ;
438+ while (!extendParentRoots .isEmpty ()) {
439+ if (extendPaths .contains (extendPath .orElse ("" ))) {
440+ addError (
441+ TemplateError .fromException (
442+ new ExtendsTagCycleException (
443+ extendPath .orElse ("" ),
444+ context .getExtendPathStack ().getTopLineNumber (),
445+ context .getExtendPathStack ().getTopStartPosition ()
446+ )
451447 )
452- .get ()
453- ) {
454- String currentPath = closeableCurrentPath
455- .value ()
456- .unwrapOrElseThrow (Function .identity ());
457- Node parentRoot = extendParentRoots .removeFirst ();
458- if (context .getDeferredTokens ().size () > numDeferredTokensBefore ) {
459- ignoredOutput .append (
460- output
461- .getNodes ()
462- .stream ()
463- .filter (node -> node instanceof RenderedOutputNode )
464- .map (OutputNode ::getValue )
465- .collect (Collectors .joining ())
466448 );
449+ break ;
467450 }
468- numDeferredTokensBefore = context .getDeferredTokens ().size ();
469- output = new OutputList (config .getMaxOutputSize ());
470- output .addNode (pathSetter );
471- boolean hasNestedExtends = false ;
472- for (Node node : parentRoot .getChildren ()) {
473- lineNumber = node .getLineNumber () - 1 ; // The line number is off by one when rendering the extend parent
474- position = node .getStartPosition ();
475- try {
476- OutputNode out = node .render (this );
477- output .addNode (out );
478- if (isExtendsTag (node )) {
479- hasNestedExtends = true ;
451+ extendPaths .add (extendPath .orElse ("" ));
452+ try (
453+ AutoCloseableImpl <Result <String , TagCycleException >> closeableCurrentPath =
454+ context
455+ .getCurrentPathStack ()
456+ .closeablePush (
457+ extendPath .orElse ("" ),
458+ context .getExtendPathStack ().getTopLineNumber (),
459+ context .getExtendPathStack ().getTopStartPosition ()
460+ )
461+ .get ()
462+ ) {
463+ String currentPath = closeableCurrentPath
464+ .value ()
465+ .unwrapOrElseThrow (Function .identity ());
466+ Node parentRoot = extendParentRoots .removeFirst ();
467+ if (context .getDeferredTokens ().size () > numDeferredTokensBefore ) {
468+ ignoredOutput .append (
469+ output
470+ .getNodes ()
471+ .stream ()
472+ .filter (node -> node instanceof RenderedOutputNode )
473+ .map (OutputNode ::getValue )
474+ .collect (Collectors .joining ())
475+ );
476+ }
477+ numDeferredTokensBefore = context .getDeferredTokens ().size ();
478+ output = new OutputList (config .getMaxOutputSize ());
479+ output .addNode (pathSetter );
480+ boolean hasNestedExtends = false ;
481+ for (Node node : parentRoot .getChildren ()) {
482+ lineNumber = node .getLineNumber () - 1 ; // The line number is off by one when rendering the extend parent
483+ position = node .getStartPosition ();
484+ try {
485+ OutputNode out = node .render (this );
486+ output .addNode (out );
487+ if (isExtendsTag (node )) {
488+ hasNestedExtends = true ;
489+ }
490+ } catch (OutputTooBigException e ) {
491+ addError (TemplateError .fromOutputTooBigException (e ));
492+ return output .getValue ();
480493 }
481- } catch (OutputTooBigException e ) {
482- addError (TemplateError .fromOutputTooBigException (e ));
483- return output .getValue ();
484494 }
495+ Optional <String > currentExtendPath = context .getExtendPathStack ().pop ();
496+ extendPath =
497+ hasNestedExtends ? currentExtendPath : context .getExtendPathStack ().peek ();
498+ basePath = Optional .of (currentPath );
485499 }
486- Optional <String > currentExtendPath = context .getExtendPathStack ().pop ();
487- extendPath =
488- hasNestedExtends ? currentExtendPath : context .getExtendPathStack ().peek ();
489- basePath = Optional .of (currentPath );
490500 }
491501 }
492- }
493502
494- int numDeferredTokensBefore = context .getDeferredTokens ().size ();
495- resolveBlockStubs (output );
496- if (context .getDeferredTokens ().size () > numDeferredTokensBefore ) {
497- pathSetter .setValue (
498- EagerReconstructionUtils .buildBlockOrInlineSetTag (
499- RelativePathResolver .CURRENT_PATH_CONTEXT_KEY ,
500- basePath ,
501- this
502- )
503- );
504- }
503+ int numDeferredTokensBefore = context .getDeferredTokens ().size ();
504+ resolveBlockStubs (output );
505+ if (context .getDeferredTokens ().size () > numDeferredTokensBefore ) {
506+ pathSetter .setValue (
507+ EagerReconstructionUtils .buildBlockOrInlineSetTag (
508+ RelativePathResolver .CURRENT_PATH_CONTEXT_KEY ,
509+ basePath ,
510+ this
511+ )
512+ );
513+ }
505514
506- if (ignoredOutput .length () > 0 ) {
507- return (
508- EagerReconstructionUtils .labelWithNotes (
509- EagerReconstructionUtils .wrapInTag (
510- ignoredOutput .toString (),
511- DoTag .TAG_NAME ,
512- this ,
513- false
514- ),
515- IGNORED_OUTPUT_FROM_EXTENDS_NOTE ,
516- this
517- ) +
518- output .getValue ()
519- );
515+ if (ignoredOutput .length () > 0 ) {
516+ return (
517+ EagerReconstructionUtils .labelWithNotes (
518+ EagerReconstructionUtils .wrapInTag (
519+ ignoredOutput .toString (),
520+ DoTag .TAG_NAME ,
521+ this ,
522+ false
523+ ),
524+ IGNORED_OUTPUT_FROM_EXTENDS_NOTE ,
525+ this
526+ ) +
527+ output .getValue ()
528+ );
529+ }
530+ return output .getValue ();
531+ } finally {
532+ if (pushed ) {
533+ JinjavaInterpreter .popCurrent ();
534+ }
520535 }
521- return output .getValue ();
522536 }
523537
524538 private void resolveBlockStubs (OutputList output ) {
0 commit comments