Skip to content

Commit

Permalink
Qute - remove standalone lines by default
Browse files Browse the repository at this point in the history
- resolves #8753
  • Loading branch information
mkouba committed Jun 29, 2020
1 parent 0050f98 commit b2f1949
Show file tree
Hide file tree
Showing 13 changed files with 356 additions and 57 deletions.
49 changes: 49 additions & 0 deletions docs/src/main/asciidoc/qute-reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,55 @@ A closing curly bracket (`}`) is ignored if not inside an expression/tag.

TIP: It is also possible to use escape sequences `\{` and `\}` to insert delimiters in the text. In fact, an escape sequence is usually only needed for the start delimiter, ie. `\\{foo}` will be rendered as `{foo}` (no evaluation will happen).

=== Removing Standalone Lines From the Template

By default, the parser removes standalone lines from the template output.
A *standalone line* is a line that contains only section tags (e.g. `{#each}` and `{/each}`), parameter declarations (e.g. `{@org.acme.Foo foo}`) and whitespace characters.
The default behavior can be disabled by setting the property `quarkus.qute.remove-standalone-lines` to `false`.

.Template
[source,html]
----
<html>
<body>
<ul>
{#for item in items} <1>
<li>{item.name}</li> <2>
{/for} <3>
</ul>
<body>
</html>
----
<1> This is a standalone line and will be removed.
<2> This is not a standalone line as it contains non-whitespace characters and an expression.
<3> This is a standalone line and will be removed.

.Output
[source,html]
----
<html>
<body>
<ul>
<li>Foo</li>
</ul>
<body>
</html>
----

.Output with `quarkus.qute.remove-standalone-lines=false`
[source,html]
----
<html>
<body>
<ul>
<li>Foo</li>
</ul>
<body>
</html>
----

==== Expressions

An expression consists of:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package io.quarkus.qute.deployment.removestandalonelines;

import static org.junit.jupiter.api.Assertions.assertEquals;

import javax.inject.Inject;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.qute.Template;
import io.quarkus.test.QuarkusUnitTest;

public class DoNotRemoveStandaloneLinesTest {

@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addAsResource(new StringAsset("{#for i in total}\n"
+ "{i}:\n"
+ "{/for}"), "templates/loop.html")
.addAsResource(new StringAsset("quarkus.qute.remove-standalone-lines=false"), "application.properties"));

@Inject
Template loop;

@Test
public void testLines() {
assertEquals("\n1:\n\n2:\n\n3:\n", loop.data("total", 3).render());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ public EngineProducer(QuteContext context, Event<EngineBuilder> event) {
// Fallback reflection resolver
builder.addValueResolver(new ReflectionValueResolver());

// Remove standalone lines if desired
builder.removeStandaloneLines(context.getConfig().removeStandaloneLines);

// Allow anyone to customize the builder
event.fire(builder);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,11 @@ public class QuteConfig {
@ConfigItem(defaultValue = "qute.html,qute.txt,html,txt")
public List<String> suffixes;

/**
* Specify whether the parser should remove standalone lines from the output. A standalone line is a line that contains
* only section tags, parameter declarations and whitespace characters.
*/
@ConfigItem(defaultValue = "true")
public boolean removeStandaloneLines;

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@
*/
public final class EngineBuilder {

private final Map<String, SectionHelperFactory<?>> sectionHelperFactories;
private final List<ValueResolver> valueResolvers;
private final List<NamespaceResolver> namespaceResolvers;
private final List<TemplateLocator> locators;
private final List<ResultMapper> resultMappers;
private Function<String, SectionHelperFactory<?>> sectionHelperFunc;
private final List<ParserHook> parserHooks;
final Map<String, SectionHelperFactory<?>> sectionHelperFactories;
final List<ValueResolver> valueResolvers;
final List<NamespaceResolver> namespaceResolvers;
final List<TemplateLocator> locators;
final List<ResultMapper> resultMappers;
Function<String, SectionHelperFactory<?>> sectionHelperFunc;
final List<ParserHook> parserHooks;
boolean removeStandaloneLines;

EngineBuilder() {
this.sectionHelperFactories = new HashMap<>();
Expand Down Expand Up @@ -137,9 +138,24 @@ public EngineBuilder computeSectionHelper(Function<String, SectionHelperFactory<
return this;
}

/**
* Specify whether the parser should remove standalone lines from the output. A standalone line is a line that contains
* only section tags, parameter declarations and whitespace characters.
*
* @param value
* @return self
*/
public EngineBuilder removeStandaloneLines(boolean value) {
this.removeStandaloneLines = value;
return this;
}

/**
*
* @return a new engine instance
*/
public Engine build() {
return new EngineImpl(sectionHelperFactories, valueResolvers, namespaceResolvers, locators, resultMappers,
sectionHelperFunc, parserHooks);
return new EngineImpl(this);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,15 @@ class EngineImpl implements Engine {
private final PublisherFactory publisherFactory;
private final AtomicLong idGenerator = new AtomicLong(0);
private final List<ParserHook> parserHooks;
final boolean removeStandaloneLines;

EngineImpl(Map<String, SectionHelperFactory<?>> sectionHelperFactories, List<ValueResolver> valueResolvers,
List<NamespaceResolver> namespaceResolvers, List<TemplateLocator> locators,
List<ResultMapper> resultMappers, Function<String, SectionHelperFactory<?>> sectionHelperFunc,
List<ParserHook> parserHooks) {
this.sectionHelperFactories = Collections.unmodifiableMap(new HashMap<>(sectionHelperFactories));
this.valueResolvers = sort(valueResolvers);
this.namespaceResolvers = ImmutableList.copyOf(namespaceResolvers);
EngineImpl(EngineBuilder builder) {
this.sectionHelperFactories = Collections.unmodifiableMap(new HashMap<>(builder.sectionHelperFactories));
this.valueResolvers = sort(builder.valueResolvers);
this.namespaceResolvers = ImmutableList.copyOf(builder.namespaceResolvers);
this.evaluator = new EvaluatorImpl(this.valueResolvers);
this.templates = new ConcurrentHashMap<>();
this.locators = sort(locators);
this.locators = sort(builder.locators);
ServiceLoader<PublisherFactory> loader = ServiceLoader.load(PublisherFactory.class);
Iterator<PublisherFactory> iterator = loader.iterator();
if (iterator.hasNext()) {
Expand All @@ -64,9 +62,10 @@ class EngineImpl implements Engine {
"Multiple reactive factories found: " + StreamSupport.stream(loader.spliterator(), false)
.map(Object::getClass).map(Class::getName).collect(Collectors.joining(",")));
}
this.resultMappers = sort(resultMappers);
this.sectionHelperFunc = sectionHelperFunc;
this.parserHooks = parserHooks;
this.resultMappers = sort(builder.resultMappers);
this.sectionHelperFunc = builder.sectionHelperFunc;
this.parserHooks = ImmutableList.copyOf(builder.parserHooks);
this.removeStandaloneLines = builder.removeStandaloneLines;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.quarkus.qute;

/**
* A line separator.
*/
public class LineSeparatorNode extends TextNode {

public LineSeparatorNode(String value, Origin origin) {
super(value, origin);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.quarkus.qute;

import java.util.function.Consumer;

/**
* Template parameter declaration.
*/
public class ParameterDeclarationNode extends TextNode {

public ParameterDeclarationNode(String value, Origin origin) {
super(value, origin);
}

@Override
public void process(Consumer<String> consumer) {
}

}
Loading

0 comments on commit b2f1949

Please sign in to comment.