-
Notifications
You must be signed in to change notification settings - Fork 170
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Preserve Raw Tags config #518
Changes from 8 commits
f632489
4f120e5
2798066
09f47a2
dd642d0
cc431d4
229b277
17c5a1c
bccbc98
277cc64
1e041b1
05b5b9c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -78,6 +78,7 @@ public enum Library { | |
private final Set<String> resolvedFunctions = new HashSet<>(); | ||
|
||
private Set<Node> deferredNodes = new HashSet<>(); | ||
private boolean hasPreservedRawTags = false; | ||
|
||
private final ExpTestLibrary expTestLibrary; | ||
private final FilterLibrary filterLibrary; | ||
|
@@ -290,6 +291,21 @@ public Set<Node> getDeferredNodes() { | |
return ImmutableSet.copyOf(deferredNodes); | ||
} | ||
|
||
public void handlePreservedRawTag() { | ||
hasPreservedRawTags = true; | ||
if (getParent() != null) { | ||
Context parent = getParent(); | ||
//Ignore global context | ||
if (parent.getParent() != null) { | ||
getParent().handlePreservedRawTag(); | ||
} | ||
} | ||
} | ||
|
||
public boolean getHasPreservedRawTags() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see this function is used. Is this needed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's for rendering implementations such as with HubSpot's internal pre-renderer There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I am missing the whole picture. Is this the case, the caller set the config to preserve raw tags, later it wants to confirm it did render with the flag set? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So if the caller sets to preserve raw tags, but there are no raw tags to preserve and no deferred values, the pre-rendered template can be served as-is. If however, there are any deferred values, then the second render will also get deferred until later. Finally, if there are no deferred values, but raw tags are preserved, then the second-pass should happen immediately with the flag off to remove the raw tags and the result can be served as-is. This is because there isn't a way of knowing if there are going to be deferred values down the line so it must always preserve raw tags if the flag is set. 3 examples assuming Example 1, no deferred values, but a raw tag is preserved:
With
Since there are no deferred values, it should be rendered again with
Example 2, there are no deferred values or raw tags preserved:
With
Since there are no deferred values or preserved tags, the output of the first render can be served as-is. Example 3, there is a deferred value and preserved raw tag:
With
Since there is a deferred variable, it should be rendered again at serve-time with
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the detailed examples. It helps a lot. But I still don't see where it needs to call There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you're mistaking the config option for this. The config option tells the interpreter to preserve the raw tags. Essentially, the method lets the caller know if any raw tags were preserved. It prevents an unnecessary second pass from happening. If this method didn't exist, it wouldn't break anything, but Example 2 would have an extra rendering call that would yield the same result, which can be avoided by using this method. There isn't a method to set There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, my bad. I mis-read it. I am OK with this. However, if we do not have this, as you said, in example 2, we would have an extra rendering call -- it should be fast because there is nothing to render. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is true. I think it would be a minimal tradeoff of speed for more simplicity, so I'll just take this out. |
||
return hasPreservedRawTags; | ||
} | ||
|
||
public List<? extends Node> getSuperBlock() { | ||
if (superBlock != null) { | ||
return superBlock; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -220,4 +220,24 @@ public void itLimitsOutputSizeWhenSumOfNodeSizesExceedsMax() { | |
assertThat(renderResult.getErrors().get(0).getMessage()) | ||
.contains("OutputTooBigException"); | ||
} | ||
|
||
@Test | ||
public void itCanPreserveRawTags() { | ||
JinjavaConfig preserveRawTagsConfig = JinjavaConfig | ||
.newBuilder() | ||
.withPreserveRawTags(true) | ||
.build(); | ||
String input = "1{% raw %}2{% endraw %}3"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you also add a test for deferred values? I thought deferred values will not get evaluated normally. Do they get evaluated inside There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My testing shows that deferred inside raw does not get evaluated either. https://github.com/HubSpot/jinjava/compare/test-deferred?expand=1 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nothing, including deferred tags, will get evaluated inside There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In my test above, the deferred values do not get evaluated in the second rendering (there is no preserveRawTags) . Maybe we are not talking about the same case? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After line 83:
In the second pass, deferred values will no longer be deferred (such as a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think what Jack meant by second pass is another renderer pass without having There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, what is the use case for those? First round rendering makes it deferred, then second round makes it not deferred, but still don't want to render it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This should display for someone like:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We wouldn't want it to render like:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Got it. Thanks. |
||
String normalOutput = "123"; | ||
String preservedOutput = "1{% raw %}2{% endraw %}3"; | ||
|
||
RenderResult renderResult = new Jinjava().renderForResult(input, new HashMap<>()); | ||
assertThat(renderResult.getOutput()).isEqualTo(normalOutput); | ||
assertThat(renderResult.hasErrors()).isFalse(); | ||
|
||
renderResult = | ||
new Jinjava(preserveRawTagsConfig).renderForResult(input, new HashMap<>()); | ||
assertThat(renderResult.getOutput()).isEqualTo(preservedOutput); | ||
assertThat(renderResult.hasErrors()).isFalse(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{% raw %}{{ deferred }}{% endraw %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this check all the way up the stack (excluding global) instead of just one level?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not too sure what you mean. I am doing a recursive call, which I believe checks up the stack, excluding global:
getParent().handlePreservedRawTag();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I was looking for a
while
and I missed the recursion.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess
if (parent.getParent() != null) {
will execute thehandlePreservedRawTag()
for Global as well. Can you verify whether we need to haveparent.getParent().getParent() != null
to exclude the global one?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like in #449, we don't want the shared global context to be altered here as it can be shared across threads. My goal with marking a context as
hasPreservedTags
is so that we know that a second pass must always be done if raw tags get preserved.In the instance that we preserve all the raw tags, but nothing gets deferred, a second pass can be done when pre-rendering. If something is deferred, that second pass will happen at serve-time. I want to exclude it for global because I just want it to mark for one run of
renderForResult
as mentioned here: #447.Does that answer what you were wondering?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I misread that question. We only need to check if the parent of what we are calling
handlePreservedTag()
on is not null. I think maybe line 300:getParent().handlePreservedRawTag()
is confusing, as it would make more sense for it to beparent.handlePreservedRawTag()
.The
if
statement is checking to make sure thatparent
's parent is not null, if so then handle the preserved raw tag forparent
With a context tree shape like
G-a-b
, here's some sudo-sequence-code that uses questionable syntax: