Skip to content

Commit

Permalink
Add feature to ignore parse errors when doing nested interpretation
Browse files Browse the repository at this point in the history
  • Loading branch information
jasmith-hs committed Sep 3, 2024
1 parent 4f17919 commit 72d938f
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 11 deletions.
33 changes: 33 additions & 0 deletions src/main/java/com/hubspot/jinjava/interpret/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,23 @@ public TemporaryValueClosable<Boolean> withUnwrapRawOverride() {
return temporaryValueClosable;
}

public boolean isIgnoreParseErrors() {
return contextConfiguration.isIgnoreParseErrors();
}

private void setIgnoreParseErrors(boolean ignoreParseErrors) {
contextConfiguration = contextConfiguration.withIgnoreParseErrors(ignoreParseErrors);
}

public TemporaryValueClosable<Boolean> withIgnoreParseErrors() {
TemporaryValueClosable<Boolean> temporaryValueClosable = new TemporaryValueClosable<>(
isIgnoreParseErrors(),
this::setIgnoreParseErrors
);
setIgnoreParseErrors(true);
return temporaryValueClosable;
}

public static class TemporaryValueClosable<T> implements AutoCloseable {

private final T previousValue;
Expand All @@ -829,10 +846,26 @@ private TemporaryValueClosable(T previousValue, Consumer<T> resetValueConsumer)
this.resetValueConsumer = resetValueConsumer;
}

public static <T> TemporaryValueClosable<T> noOp() {
return new NoOpTemporaryValueClosable<>();
}

@Override
public void close() {
resetValueConsumer.accept(previousValue);
}

private static class NoOpTemporaryValueClosable<T> extends TemporaryValueClosable<T> {

private NoOpTemporaryValueClosable() {
super(null, null);
}

@Override
public void close() {
// No-op
}
}
}

public Node getCurrentNode() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,12 @@ default boolean isPartialMacroEvaluation() {
default boolean isUnwrapRawOverride() {
return false;
}

/**
* When trying nested interpretation, parsing errors are likely. This flag avoids propogating to differentiate between static and dynamic parsing errors.
*/
@Default
default boolean isIgnoreParseErrors() {
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.hubspot.jinjava.el.ExpressionResolver;
import com.hubspot.jinjava.el.ext.DeferredParsingException;
import com.hubspot.jinjava.el.ext.ExtendedParser;
import com.hubspot.jinjava.interpret.Context.TemporaryValueClosable;
import com.hubspot.jinjava.interpret.TemplateError.ErrorItem;
import com.hubspot.jinjava.interpret.TemplateError.ErrorReason;
import com.hubspot.jinjava.interpret.TemplateError.ErrorType;
Expand Down Expand Up @@ -83,6 +84,8 @@ public class JinjavaInterpreter implements PyishSerializable {

public static final String OUTPUT_UNDEFINED_VARIABLES_ERROR =
"OUTPUT_UNDEFINED_VARIABLES_ERROR";
public static final String IGNORE_NESTED_INTERPRETATION_PARSE_ERRORS =
"IGNORE_NESTED_INTERPRETATION_PARSE_ERRORS";
private final Multimap<String, BlockInfo> blocks = ArrayListMultimap.create();
private final LinkedList<Node> extendParentRoots = new LinkedList<>();
private final Map<String, RevertibleObject> revertibleObjects = new HashMap<>();
Expand Down Expand Up @@ -259,7 +262,7 @@ public String renderFlat(String template) {
public String renderFlat(String template, long renderLimit) {
int depth = context.getRenderDepth();

try {
try (TemporaryValueClosable<Boolean> c = ignoreParseErrorsIfActivated()) {
if (depth > config.getMaxRenderDepth()) {
ENGINE_LOG.warn("Max render depth exceeded: {}", Integer.toString(depth));
return template;
Expand All @@ -272,6 +275,17 @@ public String renderFlat(String template, long renderLimit) {
}
}

private TemporaryValueClosable<Boolean> ignoreParseErrorsIfActivated() {
return config
.getFeatures()
.getActivationStrategy(
JinjavaInterpreter.IGNORE_NESTED_INTERPRETATION_PARSE_ERRORS
)
.isActive(context)
? context.withIgnoreParseErrors()
: TemporaryValueClosable.noOp();
}

/**
* Parse the given string into a root Node, and then renders it processing extend parents.
*
Expand Down
25 changes: 15 additions & 10 deletions src/main/java/com/hubspot/jinjava/tree/TreeParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public Node buildTree() {

do {
if (parent != root) {
interpreter.addError(
maybeAddError(
TemplateError.fromException(
new MissingEndTagException(
((TagNode) parent).getEndName(),
Expand Down Expand Up @@ -113,7 +113,7 @@ private Node nextNode() {

if (token.getType() == symbols.getFixed()) {
if (token instanceof UnclosedToken) {
interpreter.addError(
maybeAddError(
new TemplateError(
ErrorType.WARNING,
ErrorReason.SYNTAX_ERROR,
Expand All @@ -134,7 +134,7 @@ private Node nextNode() {
} else if (token.getType() == symbols.getNote()) {
String commentClosed = symbols.getClosingComment();
if (!token.getImage().endsWith(commentClosed)) {
interpreter.addError(
maybeAddError(
new TemplateError(
ErrorType.WARNING,
ErrorReason.SYNTAX_ERROR,
Expand All @@ -148,7 +148,7 @@ private Node nextNode() {
);
}
} else {
interpreter.addError(
maybeAddError(
TemplateError.fromException(
new UnexpectedTokenException(
token.getImage(),
Expand Down Expand Up @@ -237,13 +237,11 @@ private Node tag(TagToken tagToken) {
try {
tag = interpreter.getContext().getTag(tagToken.getTagName());
if (tag == null) {
interpreter.addError(
TemplateError.fromException(new UnknownTagException(tagToken))
);
maybeAddError(TemplateError.fromException(new UnknownTagException(tagToken)));
return null;
}
} catch (DisabledException e) {
interpreter.addError(
maybeAddError(
new TemplateError(
ErrorType.FATAL,
ErrorReason.DISABLED,
Expand Down Expand Up @@ -292,7 +290,7 @@ private void endTag(Tag tag, TagToken tagToken) {
hasMatchingStartTag = true;
break;
} else {
interpreter.addError(
maybeAddError(
TemplateError.fromException(
new TemplateSyntaxException(
tagToken.getImage(),
Expand All @@ -305,7 +303,7 @@ private void endTag(Tag tag, TagToken tagToken) {
}
}
if (!hasMatchingStartTag) {
interpreter.addError(
maybeAddError(
new TemplateError(
ErrorType.WARNING,
ErrorReason.SYNTAX_ERROR,
Expand All @@ -326,4 +324,11 @@ private boolean isTrimmingEnabledForToken(Token token, JinjavaConfig jinjavaConf
}
return jinjavaConfig.getLegacyOverrides().isUseTrimmingForNotesAndExpressions();
}

private void maybeAddError(TemplateError templateError) {
if (interpreter.getContext().isIgnoreParseErrors()) {
return;
}
interpreter.addError(templateError);
}
}

0 comments on commit 72d938f

Please sign in to comment.