Skip to content

Commit 8b313d5

Browse files
committed
Fix to ensure that when set tags are reconstructed, do-update's are reconstructed if that set variable should get imported into an alias
1 parent dfcd35b commit 8b313d5

9 files changed

Lines changed: 65 additions & 26 deletions

src/main/java/com/hubspot/jinjava/lib/tag/eager/EagerSetTagStrategy.java

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -150,23 +150,30 @@ protected PrefixToPreserveState getPrefixToPreserveState(
150150
return prefixToPreserveState;
151151
}
152152

153-
protected String getSuffixToPreserveState(
153+
public static String getSuffixToPreserveState(
154154
String variables,
155155
JinjavaInterpreter interpreter
156156
) {
157+
if (variables.isEmpty()) {
158+
return "";
159+
}
157160
StringBuilder suffixToPreserveState = new StringBuilder();
158161
Optional<String> maybeTemporaryImportAlias = AliasedEagerImportingStrategy.getTemporaryImportAlias(
159162
interpreter.getContext()
160163
);
161-
if (maybeTemporaryImportAlias.isPresent()) {
164+
if (
165+
maybeTemporaryImportAlias.isPresent() &&
166+
!AliasedEagerImportingStrategy.isTemporaryImportAlias(variables) &&
167+
!interpreter.getContext().getMetaContextVariables().contains(variables)
168+
) {
162169
String updateString = getUpdateString(variables);
170+
171+
// Don't need to render because the temporary import alias's value is always deferred, and rendering will do nothing
163172
suffixToPreserveState.append(
164-
interpreter.render(
165-
EagerReconstructionUtils.buildDoUpdateTag(
166-
maybeTemporaryImportAlias.get(),
167-
updateString,
168-
interpreter
169-
)
173+
EagerReconstructionUtils.buildDoUpdateTag(
174+
maybeTemporaryImportAlias.get(),
175+
updateString,
176+
interpreter
170177
)
171178
);
172179
}

src/main/java/com/hubspot/jinjava/lib/tag/eager/importing/AliasedEagerImportingStrategy.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,21 @@
2222
import java.util.stream.Stream;
2323

2424
public class AliasedEagerImportingStrategy implements EagerImportingStrategy {
25-
private static final String TEMPORARY_IMPORT_ALIAS_FORMAT = "__temp_import_alias_%d__";
25+
private static final String TEMPORARY_IMPORT_ALIAS_PREFIX = "__temp_import_alias_";
26+
private static final String TEMPORARY_IMPORT_ALIAS_FORMAT =
27+
TEMPORARY_IMPORT_ALIAS_PREFIX + "%d__";
2628

2729
public static Optional<String> getTemporaryImportAlias(Context context) {
2830
return context
2931
.getImportResourceAlias()
3032
.map(AliasedEagerImportingStrategy::getTemporaryImportAlias);
3133
}
3234

35+
public static boolean isTemporaryImportAlias(String varName) {
36+
// This is just faster than checking a regex
37+
return varName.startsWith(TEMPORARY_IMPORT_ALIAS_PREFIX);
38+
}
39+
3340
private static String getTemporaryImportAlias(String fullAlias) {
3441
return String.format(
3542
TEMPORARY_IMPORT_ALIAS_FORMAT,
@@ -83,10 +90,7 @@ public void setup(JinjavaInterpreter child) {
8390
child.getContext().getScope().put(Context.IMPORT_RESOURCE_ALIAS_KEY, fullImportAlias);
8491
child.getContext().put(Context.IMPORT_RESOURCE_ALIAS_KEY, fullImportAlias);
8592
constructFullAliasPathMap(currentImportAlias, child);
86-
Map<String, Object> currentContextAliasMap = getMapForCurrentContextAlias(
87-
currentImportAlias,
88-
child
89-
);
93+
getMapForCurrentContextAlias(currentImportAlias, child);
9094
importingData
9195
.getOriginalInterpreter()
9296
.getContext()
@@ -133,7 +137,7 @@ public String getFinalOutput(
133137
) +
134138
wrapInChildScope(
135139
EagerImportingStrategy.getSetTagForDeferredChildBindings(
136-
importingData.getOriginalInterpreter(),
140+
child,
137141
currentImportAlias,
138142
child.getContext()
139143
) +

src/main/java/com/hubspot/jinjava/util/EagerReconstructionUtils.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import com.hubspot.jinjava.lib.tag.SetTag;
2222
import com.hubspot.jinjava.lib.tag.eager.DeferredToken;
2323
import com.hubspot.jinjava.lib.tag.eager.EagerExecutionResult;
24+
import com.hubspot.jinjava.lib.tag.eager.EagerSetTagStrategy;
25+
import com.hubspot.jinjava.lib.tag.eager.importing.AliasedEagerImportingStrategy;
2426
import com.hubspot.jinjava.mode.EagerExecutionMode;
2527
import com.hubspot.jinjava.objects.serialization.PyishBlockSetSerializable;
2628
import com.hubspot.jinjava.objects.serialization.PyishObjectMapper;
@@ -474,11 +476,15 @@ public static String buildSetTag(
474476

475477
StringJoiner vars = new StringJoiner(",");
476478
StringJoiner values = new StringJoiner(",");
479+
StringJoiner varsRequiringSuffix = new StringJoiner(",");
477480
deferredValuesToSet.forEach(
478481
(key, value) -> {
479482
// This ensures they are properly aligned to each other.
480483
vars.add(key);
481484
values.add(value);
485+
if (!AliasedEagerImportingStrategy.isTemporaryImportAlias(value)) {
486+
varsRequiringSuffix.add(key);
487+
}
482488
}
483489
);
484490
LengthLimitingStringJoiner result = new LengthLimitingStringJoiner(
@@ -493,6 +499,10 @@ public static String buildSetTag(
493499
.add(values.toString())
494500
.add(interpreter.getConfig().getTokenScannerSymbols().getExpressionEndWithTag());
495501
String image = result.toString();
502+
String suffix = EagerSetTagStrategy.getSuffixToPreserveState(
503+
varsRequiringSuffix.toString(),
504+
interpreter
505+
);
496506
// Don't defer if we're sticking with the new value
497507
if (registerDeferredToken) {
498508
return (
@@ -505,10 +515,11 @@ public static String buildSetTag(
505515
.build()
506516
)
507517
) +
508-
image
518+
image +
519+
suffix
509520
);
510521
}
511-
return image;
522+
return (image + suffix);
512523
}
513524

514525
/**
@@ -552,6 +563,7 @@ public static String buildBlockSetTag(
552563
.add("end" + SetTag.TAG_NAME)
553564
.add(interpreter.getConfig().getTokenScannerSymbols().getExpressionEndWithTag());
554565
String image = blockSetTokenBuilder + value + endTokenBuilder;
566+
String suffix = EagerSetTagStrategy.getSuffixToPreserveState(name, interpreter);
555567
if (registerDeferredToken) {
556568
return (
557569
new PrefixToPreserveState(
@@ -567,10 +579,11 @@ public static String buildBlockSetTag(
567579
.build()
568580
)
569581
) +
570-
image
582+
image +
583+
suffix
571584
);
572585
}
573-
return image;
586+
return image + suffix;
574587
}
575588

576589
public static String buildDoUpdateTag(

src/test/java/com/hubspot/jinjava/EagerTest.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,13 +1008,17 @@ public void itHandlesDoubleImportModificationSecondPass() {
10081008

10091009
@Test
10101010
public void itHandlesSameNameImportVar() {
1011-
String template = expectedTemplateInterpreter.getFixtureTemplate(
1011+
expectedTemplateInterpreter.assertExpectedOutputNonIdempotent(
10121012
"handles-same-name-import-var"
10131013
);
1014-
JinjavaInterpreter.getCurrent().render(template);
1015-
// No longer allows importing a file that uses the same alias as a variable declared in the import file
1016-
assertThat(JinjavaInterpreter.getCurrent().getContext().getDeferredNodes())
1017-
.isNotEmpty();
1014+
}
1015+
1016+
@Test
1017+
public void itHandlesSameNameImportVarSecondPass() {
1018+
interpreter.getContext().put("deferred", "resolved");
1019+
expectedTemplateInterpreter.assertExpectedNonEagerOutput(
1020+
"handles-same-name-import-var.expected"
1021+
);
10181022
}
10191023

10201024
@Test

src/test/java/com/hubspot/jinjava/lib/tag/eager/EagerImportTagTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ public void itHandlesQuadLayerInDeferredIf() {
397397
);
398398
assertThat(result)
399399
.isEqualTo(
400-
"{% if deferred %}{% do %}{% set current_path = 'import-tree-b.jinja' %}{% set __temp_import_alias_98__ = {} %}{% for __ignored__ in [0] %}{% set a = {'foo_a': 'a', 'import_resource_path': 'import-tree-a.jinja', 'something': 'somn'} %}{% do %}{% set current_path = 'import-tree-a.jinja' %}{% set __temp_import_alias_95701__ = {} %}{% for __ignored__ in [0] %}{% set something = 'somn' %}{% do __temp_import_alias_95701__.update({'something': something}) %}\n" +
400+
"{% if deferred %}{% do %}{% set current_path = 'import-tree-b.jinja' %}{% set __temp_import_alias_98__ = {} %}{% for __ignored__ in [0] %}{% do %}{% set current_path = 'import-tree-a.jinja' %}{% set __temp_import_alias_95701__ = {} %}{% for __ignored__ in [0] %}{% set something = 'somn' %}{% do __temp_import_alias_95701__.update({'something': something}) %}\n" +
401401
"{% set foo_a = 'a' %}{% do __temp_import_alias_95701__.update({'foo_a': foo_a}) %}\n" +
402402
"{% do __temp_import_alias_95701__.update({'foo_a': 'a','import_resource_path': 'import-tree-a.jinja','something': 'somn'}) %}{% endfor %}{% set a = __temp_import_alias_95701__ %}{% set current_path = 'import-tree-b.jinja' %}{% enddo %}\n" +
403403
"{% set foo_b = 'b' + a.foo_a %}{% do __temp_import_alias_98__.update({'foo_b': foo_b}) %}\n" +
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{% do %}{% set current_path = 'filters.jinja' %}{% set __temp_import_alias_854547461__ = {} %}{% for __ignored__ in [0] %}
22
{% set bar = deferred %}{% do __temp_import_alias_854547461__.update({'bar': bar}) %}
33

4-
{% set filters = {} %}{% do filters.update(deferred) %}
4+
{% set filters = {} %}{% do __temp_import_alias_854547461__.update({'filters': filters}) %}{% do filters.update(deferred) %}
55
{% do __temp_import_alias_854547461__.update({'bar': bar,'import_resource_path': 'filters.jinja','filters': filters,'foo': 123}) %}{% endfor %}{% set filters = __temp_import_alias_854547461__ %}{% set current_path = '' %}{% enddo %}
66

77
{{ filters }}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[fn:map_entry('import_resource_path', '../settag/set-var-and-deferred.jinja'), fn:map_entry('my_var', {'my_var': {'foo': 'bar'} , 'value': 'resolved', 'import_resource_path': '../settag/set-var-and-deferred.jinja'} ), fn:map_entry('path', ''), fn:map_entry('value', 'resolved')]
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{% if deferred %}
2+
{% do %}{% set current_path = '../settag/set-var-and-deferred.jinja' %}{% set __temp_import_alias_1059697132__ = {} %}{% for __ignored__ in [0] %}{% if deferred %}
3+
{% do %}{% set path = '' %}{% do __temp_import_alias_1059697132__.update({'path': path}) %}{% set my_var = {'my_var': {'foo': 'bar'} } %}{% do __temp_import_alias_1059697132__.update({'my_var': my_var}) %}{% set path = '../settag/set-var-and-deferred.jinja' %}{% do __temp_import_alias_1059697132__.update({'path': path}) %}{% set value = null %}{% do __temp_import_alias_1059697132__.update({'value': value}) %}{% set my_var = {} %}{% do __temp_import_alias_1059697132__.update({'my_var': my_var}) %}{% set my_var = {'foo': 'bar'} %}{% do __temp_import_alias_1059697132__.update({'my_var': my_var}) %}{% set my_var = {'my_var': {'foo': 'bar'} } %}{% do __temp_import_alias_1059697132__.update({'my_var': my_var}) %}
4+
{% set value = deferred %}{% do __temp_import_alias_1059697132__.update({'value': value}) %}{% set my_var = {'my_var': {'foo': 'bar'} } %}{% do __temp_import_alias_1059697132__.update({'my_var': my_var}) %}{% do my_var.update({'value': value}) %}
5+
{% do my_var.update({'import_resource_path': '../settag/set-var-and-deferred.jinja', 'value': value}) %}{% set path = '' %}{% do __temp_import_alias_1059697132__.update({'path': path}) %}{% enddo %}
6+
{{ my_var }}
7+
{% endif %}
8+
{% do __temp_import_alias_1059697132__.update({'path': path,'import_resource_path': '../settag/set-var-and-deferred.jinja','value': value}) %}{% endfor %}{% set my_var = __temp_import_alias_1059697132__ %}{% set current_path = '' %}{% enddo %}
9+
{{ filter:dictsort.filter(my_var, ____int3rpr3t3r____, false, 'key') }}
10+
{% endif %}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{% if deferred %}
22
{% import '../settag/set-var-and-deferred.jinja' as my_var %}
3-
{{ my_var }}
3+
{{ my_var|dictsort(false, 'key') }}
44
{% endif %}

0 commit comments

Comments
 (0)