Skip to content

Commit

Permalink
When importing with an alias, reconstruct to a temporary variable rat…
Browse files Browse the repository at this point in the history
…her than directly to the alias, as there may be name clashing inside of the imported file
  • Loading branch information
jasmith-hs committed Oct 4, 2023
1 parent af980e3 commit dcf67e2
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 109 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public String getEagerTagImage(TagToken tagToken, JinjavaInterpreter interpreter
return "";
}
return EagerReconstructionUtils.wrapInTag(
eagerImportingStrategy.getFinalOutput(newPathSetter, output, childBindings),
eagerImportingStrategy.getFinalOutput(newPathSetter, output, child),
DoTag.TAG_NAME,
interpreter,
true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.google.common.annotations.Beta;
import com.hubspot.jinjava.interpret.JinjavaInterpreter;
import com.hubspot.jinjava.lib.tag.SetTag;
import com.hubspot.jinjava.lib.tag.eager.importing.AliasedEagerImportingStrategy;
import com.hubspot.jinjava.tree.TagNode;
import com.hubspot.jinjava.util.EagerReconstructionUtils;
import com.hubspot.jinjava.util.PrefixToPreserveState;
Expand Down Expand Up @@ -154,30 +155,22 @@ protected String getSuffixToPreserveState(
JinjavaInterpreter interpreter
) {
StringBuilder suffixToPreserveState = new StringBuilder();
Optional<String> maybeFullImportAlias = interpreter
.getContext()
.getImportResourceAlias();
if (maybeFullImportAlias.isPresent()) {
String currentImportAlias = maybeFullImportAlias
.get()
.substring(maybeFullImportAlias.get().lastIndexOf(".") + 1);
String filteredVariables = Arrays
.stream(variables.split(","))
.filter(var -> !var.equals(currentImportAlias))
.collect(Collectors.joining(","));
if (!filteredVariables.isEmpty()) {
String updateString = getUpdateString(filteredVariables);
suffixToPreserveState.append(
interpreter.render(
EagerReconstructionUtils.buildDoUpdateTag(
currentImportAlias,
updateString,
interpreter
)
Optional<String> maybeTemporaryImportAlias = AliasedEagerImportingStrategy.getTemporaryImportAlias(
interpreter.getContext()
);
if (maybeTemporaryImportAlias.isPresent()) {
String updateString = getUpdateString(variables);
suffixToPreserveState.append(
interpreter.render(
EagerReconstructionUtils.buildDoUpdateTag(
maybeTemporaryImportAlias.get(),
updateString,
interpreter
)
);
}
)
);
}

return suffixToPreserveState.toString();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.hubspot.jinjava.lib.tag.eager.importing;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import com.hubspot.jinjava.interpret.Context;
import com.hubspot.jinjava.interpret.DeferredValue;
import com.hubspot.jinjava.interpret.DeferredValueException;
Expand All @@ -12,18 +13,33 @@
import com.hubspot.jinjava.objects.serialization.PyishObjectMapper;
import com.hubspot.jinjava.util.EagerReconstructionUtils;
import com.hubspot.jinjava.util.PrefixToPreserveState;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.StringJoiner;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class AliasedEagerImportingStrategy implements EagerImportingStrategy {
private static final String TEMPORARY_IMPORT_ALIAS_FORMAT = "__temp_import_alias_%d__";

public static Optional<String> getTemporaryImportAlias(Context context) {
return context
.getImportResourceAlias()
.map(AliasedEagerImportingStrategy::getTemporaryImportAlias);
}

private static String getTemporaryImportAlias(String fullAlias) {
return String.format(
TEMPORARY_IMPORT_ALIAS_FORMAT,
Math.abs(Objects.hashCode(fullAlias))
);
}

private final ImportingData importingData;
private final String currentImportAlias;
private final String fullImportAlias;

@VisibleForTesting
public AliasedEagerImportingStrategy(
Expand All @@ -32,6 +48,16 @@ public AliasedEagerImportingStrategy(
) {
this.importingData = importingData;
this.currentImportAlias = currentImportAlias;
Optional<String> maybeParentImportAlias = importingData
.getOriginalInterpreter()
.getContext()
.getImportResourceAlias();
if (maybeParentImportAlias.isPresent()) {
fullImportAlias =
String.format("%s.%s", maybeParentImportAlias.get(), currentImportAlias);
} else {
fullImportAlias = currentImportAlias;
}
}

@Override
Expand All @@ -54,26 +80,17 @@ public String handleDeferredTemplateFile(DeferredValueException e) {

@Override
public void setup(JinjavaInterpreter child) {
Optional<String> maybeParentImportAlias = importingData
child.getContext().getScope().put(Context.IMPORT_RESOURCE_ALIAS_KEY, fullImportAlias);
child.getContext().put(Context.IMPORT_RESOURCE_ALIAS_KEY, fullImportAlias);
constructFullAliasPathMap(currentImportAlias, child);
Map<String, Object> currentContextAliasMap = getMapForCurrentContextAlias(
currentImportAlias,
child
);
importingData
.getOriginalInterpreter()
.getContext()
.getImportResourceAlias();
if (maybeParentImportAlias.isPresent()) {
child
.getContext()
.getScope()
.put(
Context.IMPORT_RESOURCE_ALIAS_KEY,
String.format("%s.%s", maybeParentImportAlias.get(), currentImportAlias)
);
} else {
child
.getContext()
.getScope()
.put(Context.IMPORT_RESOURCE_ALIAS_KEY, currentImportAlias);
}
constructFullAliasPathMap(currentImportAlias, child);
getMapForCurrentContextAlias(currentImportAlias, child);
.put(getTemporaryImportAlias(fullImportAlias), DeferredValue.instance());
}

@Override
Expand All @@ -84,46 +101,16 @@ public void integrateChild(JinjavaInterpreter child) {
macro.setDeferred(true);
}
}
if (
child.getContext().isDeferredExecutionMode() &&
child
.getContext()
.getDeferredTokens()
.stream()
.flatMap(deferredToken -> deferredToken.getSetDeferredWords().stream())
.collect(Collectors.toSet())
.contains(currentImportAlias)
) {
// since a child scope will be used, the import alias would not be properly reconstructed
throw new DeferredValueException(
"Same-named variable as import alias: " + currentImportAlias
);
}
Map<String, Object> childBindings = child.getContext().getSessionBindings();
childBindings.putAll(child.getContext().getGlobalMacros());
String temporaryImportAlias = getTemporaryImportAlias(fullImportAlias);
Map<String, Object> mapForCurrentContextAlias = getMapForCurrentContextAlias(
currentImportAlias,
child
);
// Remove layers from self down to original import alias to prevent reference loops
Arrays
.stream(
child
.getContext()
.getImportResourceAlias()
.orElse(currentImportAlias)
.split("\\.")
)
.filter(
key ->
mapForCurrentContextAlias ==
(
childBindings.get(key) instanceof DeferredValue
? ((DeferredValue) childBindings.get(key)).getOriginalValue()
: childBindings.get(key)
)
)
.forEach(childBindings::remove);
childBindings.remove(temporaryImportAlias);
importingData.getOriginalInterpreter().getContext().remove(temporaryImportAlias);
// Remove meta keys
childBindings.remove(Context.GLOBAL_MACROS_SCOPE_KEY);
childBindings.remove(Context.IMPORT_RESOURCE_ALIAS_KEY);
Expand All @@ -134,24 +121,29 @@ public void integrateChild(JinjavaInterpreter child) {
public String getFinalOutput(
String newPathSetter,
String output,
Map<String, Object> childBindings
JinjavaInterpreter child
) {
String temporaryImportAlias = getTemporaryImportAlias(fullImportAlias);
return (
newPathSetter +
EagerReconstructionUtils.buildBlockOrInlineSetTagAndRegisterDeferredToken(
currentImportAlias,
EagerReconstructionUtils.buildBlockOrInlineSetTag(
temporaryImportAlias,
Collections.emptyMap(),
importingData.getOriginalInterpreter()
) +
wrapInChildScope(
importingData.getOriginalInterpreter(),
EagerImportingStrategy.getSetTagForDeferredChildBindings(
importingData.getOriginalInterpreter(),
currentImportAlias,
childBindings
child.getContext()
) +
output,
currentImportAlias
child
) +
EagerReconstructionUtils.buildSetTag(
ImmutableMap.of(currentImportAlias, temporaryImportAlias),
importingData.getOriginalInterpreter(),
true
) +
importingData.getInitialPathSetter()
);
Expand Down Expand Up @@ -229,30 +221,28 @@ private static Map<String, Object> getMapForCurrentContextAlias(
}
}

private static String wrapInChildScope(
JinjavaInterpreter interpreter,
String output,
String currentImportAlias
) {
String combined = output + getDoTagToPreserve(interpreter, currentImportAlias);
private String wrapInChildScope(String output, JinjavaInterpreter child) {
String combined =
output + getDoTagToPreserve(importingData.getOriginalInterpreter(), child);
// So that any set variables other than the alias won't exist outside the child's scope
return EagerReconstructionUtils.wrapInChildScope(combined, interpreter);
return EagerReconstructionUtils.wrapInChildScope(
combined,
importingData.getOriginalInterpreter()
);
}

@SuppressWarnings("unchecked")
private static String getDoTagToPreserve(
private String getDoTagToPreserve(
JinjavaInterpreter interpreter,
String currentImportAlias
JinjavaInterpreter child
) {
StringJoiner keyValueJoiner = new StringJoiner(",");
Object currentAliasMap = interpreter
.getContext()
.getSessionBindings()
.get(currentImportAlias);
for (Map.Entry<String, Object> entry : (
(Map<String, Object>) ((DeferredValue) currentAliasMap).getOriginalValue()
).entrySet()) {
if (entry.getKey().equals(currentImportAlias)) {
String temporaryImportAlias = getTemporaryImportAlias(fullImportAlias);
Map<String, Object> currentAliasMap = getMapForCurrentContextAlias(
currentImportAlias,
child
);
for (Map.Entry<String, Object> entry : currentAliasMap.entrySet()) {
if (entry.getKey().equals(temporaryImportAlias)) {
continue;
}
if (entry.getValue() instanceof DeferredValue) {
Expand All @@ -269,7 +259,7 @@ private static String getDoTagToPreserve(
}
if (keyValueJoiner.length() > 0) {
return EagerReconstructionUtils.buildDoUpdateTag(
currentImportAlias,
temporaryImportAlias,
"{" + keyValueJoiner.toString() + "}",
interpreter
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,7 @@ public interface EagerImportingStrategy {
void setup(JinjavaInterpreter child);

void integrateChild(JinjavaInterpreter child);
String getFinalOutput(
String newPathSetter,
String output,
Map<String, Object> childBindings
);
String getFinalOutput(String newPathSetter, String output, JinjavaInterpreter child);

static String getSetTagForDeferredChildBindings(
JinjavaInterpreter interpreter,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public void integrateChild(JinjavaInterpreter child) {
public String getFinalOutput(
String newPathSetter,
String output,
Map<String, Object> childBindings
JinjavaInterpreter child
) {
if (importingData.getOriginalInterpreter().getContext().isDeferredExecutionMode()) {
Set<String> metaContextVariables = importingData
Expand All @@ -76,7 +76,9 @@ public String getFinalOutput(
.getMetaContextVariables();
// defer imported variables
EagerReconstructionUtils.buildSetTag(
childBindings
child
.getContext()
.getSessionBindings()
.entrySet()
.stream()
.filter(
Expand All @@ -94,7 +96,7 @@ public String getFinalOutput(
EagerImportingStrategy.getSetTagForDeferredChildBindings(
importingData.getOriginalInterpreter(),
null,
childBindings
child.getContext().getSessionBindings()
) +
output +
importingData.getInitialPathSetter()
Expand Down

0 comments on commit dcf67e2

Please sign in to comment.