com.github.jknack.handlebars.Context Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aem-sdk-api Show documentation
Show all versions of aem-sdk-api Show documentation
The Adobe Experience Manager SDK
/**
* Copyright (c) 2012-2015 Edgar Espina
*
* This file is part of Handlebars.java.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.jknack.handlebars;
import static org.apache.commons.lang3.Validate.notEmpty;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.github.jknack.handlebars.context.MapValueResolver;
import com.github.jknack.handlebars.internal.path.ThisPath;
import com.github.jknack.handlebars.io.TemplateSource;
/**
* Mustache/Handlebars are contextual template engines. This class represent the
* 'context stack' of a template.
*
* - Objects and hashes should be pushed onto the context stack.
*
- All elements on the context stack should be accessible.
*
- Multiple sections per template should be permitted.
*
- Failed context lookups should be considered falsy.
*
- Dotted names should be valid for Section tags.
*
- Dotted names that cannot be resolved should be considered falsy.
*
- Dotted Names - Context Precedence: Dotted names should be resolved against former
* resolutions.
*
*
* @author edgar.espina
* @since 0.1.0
*
* @deprecated com.github.jknack.handlebars package is deprecated and marked for removal in subsequent releases which will involve removal of the handlebars dependency in AEM.
*/
@Deprecated(since = "2024-07-10")
public class Context {
/**
* Special scope for silly block param rules, implemented by handlebars.js. This context will
* check for pathed variable and resolve them against parent context.
*
* @author edgar
* @since 3.0.0
*
* @deprecated com.github.jknack.handlebars package is deprecated and marked for removal in subsequent releases which will involve removal of the handlebars dependency in AEM.
*/
@Deprecated(since = "2024-07-10")
private static class BlockParam extends Context {
/**
* A new {@link BlockParam}.
*
* @param parent Parent context.
* @param hash A hash model.
*/
protected BlockParam(final Context parent, final Map hash) {
super(hash);
this.extendedContext = new Context(new HashMap());
this.extendedContext.resolver = parent.resolver;
this.parent = parent;
this.data = parent.data;
this.resolver = parent.resolver;
}
@Override
public Object get(final List path) {
String key = path.get(0).toString();
// we must resolve this to parent context on block contexts (so tricky)
if (path.size() == 1 && key.equals("this")) {
return parent.model;
}
// path variable should resolve from parent :S
if (key.startsWith(".") && path.size() > 1) {
return parent.get(path.subList(1, path.size()));
}
return super.get(path);
}
@Override
protected Context newChildContext(final Object model) {
return new ParentFirst(model);
}
}
/**
* Context that resolve variables against parent, or fallback to default/normal lookup.
*
* @author edgar
* @since 3.0.0
*
* @deprecated com.github.jknack.handlebars package is deprecated and marked for removal in subsequent releases which will involve removal of the handlebars dependency in AEM.
*/
@Deprecated(since = "2024-07-10")
private static class ParentFirst extends Context {
/**
* Parent first lookup.
*
* @param model A model.
*/
protected ParentFirst(final Object model) {
super(model);
}
@Override
public Object get(final List path) {
Object value = parent.get(path);
if (value == null) {
return super.get(path);
}
return value;
}
@Override
protected Context newChildContext(final Object model) {
return new ParentFirst(model);
}
}
/**
* Partial context.
*
* @author edgar
* @since 4.0.5
*
* @deprecated com.github.jknack.handlebars package is deprecated and marked for removal in subsequent releases which will involve removal of the handlebars dependency in AEM.
*/
@Deprecated(since = "2024-07-10")
private static class PartialCtx extends Context {
/**
* Creates a new partial context.
*
* @param parent Parent.
* @param model Model.
* @param hash Hash.
*/
protected PartialCtx(final Context parent, final Object model, final Map hash) {
super(model);
this.extendedContext = new Context(hash);
this.extendedContext.resolver = parent.resolver;
this.extendedContext.extendedContext = new Context(Collections.emptyMap());
this.parent = parent;
this.data = parent.data;
this.resolver = parent.resolver;
}
@Override
public Object get(final List path) {
String key = path.get(0).toString();
// hash first, except for this
if (key.equals("this")) {
return super.get(path);
}
Object value = extendedContext.get(path);
if (value == null) {
return super.get(path);
}
return value;
}
}
/**
* A composite value resolver. It delegate the value resolution.
*
* @author edgar.espina
* @since 0.1.1
*
* @deprecated com.github.jknack.handlebars package is deprecated and marked for removal in subsequent releases which will involve removal of the handlebars dependency in AEM.
*/
@Deprecated(since = "2024-07-10")
private static class CompositeValueResolver implements ValueResolver {
/**
* The internal value resolvers.
*/
private List resolvers;
/**
* Creates a new {@link CompositeValueResolver}.
*
* @param resolvers The value resolvers.
*/
CompositeValueResolver(final List resolvers) {
this.resolvers = resolvers;
}
@Override
public Object resolve(final Object context, final String name) {
int i = 0;
while (i < resolvers.size()) {
Object value = resolvers.get(i).resolve(context, name);
if (value != UNRESOLVED) {
return value == null ? NULL : value;
}
i += 1;
}
return null;
}
@Override
public Object resolve(final Object context) {
int i = 0;
while (i < resolvers.size()) {
Object value = resolvers.get(i).resolve(context);
if (value != UNRESOLVED) {
return value == null ? NULL : value;
}
i += 1;
}
return null;
}
@Override
public Set> propertySet(final Object context) {
Set> propertySet = new LinkedHashSet<>();
for (ValueResolver resolver : resolvers) {
propertySet.addAll(resolver.propertySet(context));
}
return propertySet;
}
}
/**
* A context builder.
*
* @author edgar.espina
* @since 0.1.1
*
* @deprecated com.github.jknack.handlebars package is deprecated and marked for removal in subsequent releases which will involve removal of the handlebars dependency in AEM.
*/
@Deprecated(since = "2024-07-10")
public static final class Builder {
/**
* The context product.
*/
private Context context;
/**
* Creates a new context builder.
*
* @param parent The parent context. Required.
* @param model The model data.
*/
private Builder(final Context parent, final Object model) {
context = parent.newChild(model);
}
/**
* Creates a new context builder.
*
* @param model The model data.
*/
private Builder(final Object model) {
context = Context.root(model);
context.setResolver(new CompositeValueResolver(ValueResolver.defaultValueResolvers()));
}
/**
* Combine the given model using the specified name.
*
* @param name The variable's name. Required.
* @param model The model data.
* @return This builder.
*/
public Builder combine(final String name, final Object model) {
context.combine(name, model);
return this;
}
/**
* Combine all the map entries into the context stack.
*
* @param model The model data.
* @return This builder.
*/
public Builder combine(final Map model) {
context.combine(model);
return this;
}
/**
* Set the value resolvers to use.
*
* @param resolvers The value resolvers. Required.
* @return This builder.
*/
public Builder resolver(final ValueResolver... resolvers) {
notEmpty(resolvers, "At least one value-resolver must be present.");
boolean mapResolver = Stream.of(resolvers).anyMatch(MapValueResolver.class::isInstance);
if (!mapResolver) {
context.setResolver(new CompositeValueResolver(Stream.concat(Stream.of(resolvers), Stream.of(MapValueResolver.INSTANCE)).collect(Collectors.toList())));
} else {
context.setResolver(new CompositeValueResolver(Arrays.asList(resolvers)));
}
return this;
}
/**
* Add one or more value resolver to the defaults defined by
* {@link ValueResolver#defaultValueResolvers()}.
*
* @param resolvers The value resolvers. Required.
* @return This builder.
*/
public Builder push(final ValueResolver... resolvers) {
notEmpty(resolvers, "At least one value-resolver must be present.");
List merged = new ArrayList<>();
merged.addAll(ValueResolver.defaultValueResolvers());
Stream.of(resolvers).forEach(merged::add);
context.setResolver(new CompositeValueResolver(merged));
return this;
}
/**
* Build a context stack.
*
* @return A new context stack.
*/
public Context build() {
return context;
}
}
/**
* Path expression chain.
*
* @author edgar
* @since 4.0.1
*
* @deprecated com.github.jknack.handlebars package is deprecated and marked for removal in subsequent releases which will involve removal of the handlebars dependency in AEM.
*/
@Deprecated(since = "2024-07-10")
private static class PathExpressionChain implements PathExpression.Chain {
/**
* Expression path.
*/
private List path;
/**
* Cursor to move/execute the next expression.
*/
private int i = 0;
/**
* Creates a new {@link PathExpressionChain}.
*
* @param path Expression path.
*/
PathExpressionChain(final List path) {
this.path = path;
}
@Override
public Object next(final ValueResolver resolver, final Context context, final Object data) {
if (data != null && i < path.size()) {
PathExpression next = path.get(i++);
return next.eval(resolver, context, data, this);
}
return data;
}
@Override
public List path() {
return path.subList(i, path.size());
}
/**
* Reset any previous state and restart the evaluation.
*
* @param resolver Value resolver.
* @param context Context object.
* @param data Data object.
* @return A resolved value or null
.
*/
public Object eval(final ValueResolver resolver, final Context context, final Object data) {
i = 0;
Object value = next(resolver, context, data);
if (value == null) {
return i > 1 ? NULL : null;
}
return value;
}
}
/**
* Mark for fail context lookup.
*/
private static final Object NULL = new Object();
/**
* The qualified name for partials. Internal use.
*/
public static final String PARTIALS = Context.class.getName() + "#partials";
/**
* Inline partials.
*/
public static final String INLINE_PARTIALS = "__inline_partials_";
/**
* The qualified name for partials. Internal use.
*/
public static final String INVOCATION_STACK = Context.class.getName() + "#invocationStack";
/**
* Number of parameters of a helper. Internal use.
*/
public static final String PARAM_SIZE = Context.class.getName() + "#paramSize";
/**
* Last callee of a partial block. Internal use.
*/
public static final String CALLEE = Context.class.getName() + "#callee";
/**
* The parent context. Optional.
*/
protected Context parent;
/**
* The target value. Resolved as '.' or 'this' inside templates. Required.
*/
Object model;
/**
* A thread safe storage.
*/
protected Map data;
/**
* Additional, data can be stored here.
*/
protected Context extendedContext;
/**
* The value resolver.
*/
protected ValueResolver resolver;
/**
* Creates a new context.
*
* @param model The target value. Resolved as '.' or 'this' inside templates. Required.
*/
protected Context(final Object model) {
this.model = model;
this.extendedContext = null;
this.parent = null;
}
/**
* Creates a root context.
*
* @param model The target value. Resolved as '.' or 'this' inside
* templates. Required.
* @return A root context.
*/
private static Context root(final Object model) {
Context root = new Context(model);
root.extendedContext = new Context(new HashMap());
root.data = new HashMap<>();
root.data.put(PARTIALS, new HashMap());
LinkedList
© 2015 - 2024 Weber Informatics LLC | Privacy Policy