All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.thisptr.jackson.jq.internal.tree.StringInterpolation Maven / Gradle / Ivy

There is a newer version: 1.2.0
Show newest version
package net.thisptr.jackson.jq.internal.tree;

import java.util.List;
import java.util.Stack;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.TextNode;

import net.thisptr.jackson.jq.Expression;
import net.thisptr.jackson.jq.PathOutput;
import net.thisptr.jackson.jq.Scope;
import net.thisptr.jackson.jq.exception.JsonQueryException;
import net.thisptr.jackson.jq.internal.misc.Pair;
import net.thisptr.jackson.jq.path.Path;

public class StringInterpolation implements Expression {
	private final List> interpolations;
	private final String template;
	private final Expression formatter;

	public StringInterpolation(final String template, final List> interpolations, final Expression formatter) {
		this.template = template;
		this.interpolations = interpolations;
		this.formatter = formatter;
	}

	@Override
	public void apply(final Scope scope, final JsonNode in, final Path ipath, final PathOutput output, final boolean requirePath) throws JsonQueryException {
		final Stack> stack = new Stack<>();
		recurse(scope, in, output, stack, interpolations);
	}

	private void recurse(final Scope scope, final JsonNode in, final PathOutput output, final Stack> stack, final List> interpolations) throws JsonQueryException {
		if (interpolations.isEmpty()) {
			final StringBuilder builder = new StringBuilder();
			int pos = 0;
			for (int index = stack.size() - 1; index >= 0; --index) {
				final Pair head = stack.get(index);
				builder.append(template.substring(pos, head._1));
				pos = head._1;

				builder.append(head._2.isValueNode() ? head._2.asText() : head._2.toString());
			}
			builder.append(template.substring(pos));
			output.emit(new TextNode(builder.toString()), null);
		} else {
			final Pair rhead = interpolations.get(interpolations.size() - 1);
			final List> rtail = interpolations.subList(0, interpolations.size() - 1);
			rhead._2.apply(scope, in, (interpolated) -> {
				if (formatter != null) {
					formatter.apply(scope, interpolated, (formatted) -> {
						stack.push(Pair.of(rhead._1, formatted));
						recurse(scope, in, output, stack, rtail);
						stack.pop();
					});
				} else {
					stack.push(Pair.of(rhead._1, interpolated));
					recurse(scope, in, output, stack, rtail);
					stack.pop();
				}
			});
		}
	}

	@Override
	public String toString() {
		int pos = 0;
		final StringBuilder builder = new StringBuilder();
		if (formatter != null) {
			builder.append(formatter);
			builder.append(" ");
		}
		builder.append("\"");
		for (final Pair interpolation : interpolations) {
			copyEscaped(builder, template, pos, interpolation._1);
			pos = interpolation._1;
			builder.append("\\(");
			builder.append(interpolation._2);
			builder.append(")");
		}
		copyEscaped(builder, template, pos, template.length());
		builder.append("\"");
		return builder.toString();
	}

	private static void copyEscaped(final StringBuilder builder, final String text, final int begin, final int end) {
		for (int i = begin; i < end; ++i) {
			final char ch = text.charAt(i);
			switch (ch) {
				case '\\':
					builder.append("\\\\");
					break;
				case '"':
					builder.append("\\\"");
					break;
				case '\b':
					builder.append("\\b");
					break;
				case '\f':
					builder.append("\\f");
					break;
				case '\r':
					builder.append("\\r");
					break;
				case '\t':
					builder.append("\\t");
					break;
				case '\n':
					builder.append("\\n");
					break;
				default:
					builder.append(ch);
			}
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy