package xapi.test.elemental.bdd;
import com.github.javaparser.JavaParser;
import com.github.javaparser.ParseException;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.expr.UiContainerExpr;
import com.github.javaparser.ast.expr.UiExpr;
import com.github.javaparser.ast.plugin.UiTransformer;
import com.github.javaparser.ast.stmt.BlockStmt;
import com.sun.source.tree.CompilationUnitTree;
import cucumber.api.java.After;
import cucumber.api.java.Before;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import xapi.collect.X_Collect;
import xapi.collect.api.StringTo;
import xapi.dev.elemental.ElementalTemplatePlugin;
import xapi.fu.Printable;
import xapi.io.X_IO;
import xapi.javac.dev.api.JavacService;
import xapi.javac.dev.model.JavaDocument;
import xapi.util.X_String;
import static org.hamcrest.text.IsEqualIgnoringWhiteSpace.equalToIgnoringWhiteSpace;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static xapi.fu.X_Fu.notEmpty;
import static xapi.util.X_String.join;
import javax.lang.model.element.TypeElement;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
//import static org.assertj.core.api.Assertions.assertThat;
/**
*
Simple example:
Element e = `<div
class = .styleName { left: 5px } \
.styleName a { color: #579 }
onClick = this::onClick
onMouseOver = this.addClassName("hovered")
onMouseOut = this::removeClassName, "hovered"
><a
href = this::submit
> Hello world! </a></div>`;
*Consideration* for a polyglot syntax:
*
html:
shadowRoot:
div:
class = "testing"
onclick = this::onClick(*)
onmouseover = js:
alert(this.innerText);
:js
onfocus = java:
this.focused = true;
:java
Hello from inside the shadow DOM
(this div is what is actually rendered,
with any tags inside the web component injected below)
:content:
:div
:shadowRoot
div:
Hello from the external DOM.
This element is the only one visible when inspecting the element,
but it will actually be rendered inside the <content /> tag in the shadow root.
:div
:html
java:
class $X implements HasClickHandler {
boolean focused = false;
}
:java
js:
function onCreated() {
console.log("this will be automatically bound to web component lifecycle");
}
function focus() {
this.controller.@$X::focused = true;
}
:js
css:
.testing {
background-color: navy;
color: white;
}
:css
*
* @author James X. Nelson (james@wetheinter.net)
* Created on 4/9/16.
*/
public class TemplateGeneratorSteps {
private JavaDocument lastCompiled;
private StringTo<Node> compiledByName = X_Collect.newStringMap(Node.class);
@Before
public void before() {
}
@After
public void after() {
}
@Given("^compile template:$")
public void compileTemplate(List<String> lines) throws Throwable {
lastCompiled = compile(lines);
}
private JavaDocument compile(List<String> lines) throws ParseException {
final Optional<String> first = lines.stream().filter(notEmpty()).findFirst();
if (!first.isPresent()) {
throw new AssertionError("No text supplied to compile method. You sent "+lines);
}
final char start = first.get().charAt(0);
switch (start) {
case '<':
// Use HTML parser
case '{':
// Use Java parser
case '.':
case '#':
// Use CSS parser
case '@':
// Grab Processing instruction
default :
// Maybe Java references, css classes, or possibly just text
try {
final BlockStmt block = JavaParser.parseBlock(X_String.joinStrings(lines.toArray(new String[lines.size()])));
} catch (Exception e) {
}
}
final CompilationUnitTree unit = null;
final JavacService service = null;
final TypeElement type = null;
JavaDocument doc = new JavaDocument(service, unit, type);
// will throw exceptions...
return doc;
}
@Given("^compile ui with name (\\S)+:$")
public void compileTemplate(String name, List<String> lines) throws Throwable {
String src = join("\n", lines);
final UiContainerExpr ui = JavaParser.parseUiContainer(src);
compiledByName.put(name, ui);
}
@Given("^compile component with name (\\S)+:$")
public void compileComponent(String name, List<String> lines) throws Throwable {
String src = join("\n", lines);
final CompilationUnit ui = JavaParser.parse(X_IO.toStreamUtf8(src));
compiledByName.put(name, ui);
}
@Then("^source code of (\\S)+ is:$")
public void sourceCodeOfNameIs(String name, List<String> lines) throws Throwable {
String expected = lines.stream()
.map(line->line.replaceAll("\\n", "\\\\n"))
.collect(Collectors.joining("\n"));
Node ui = getNode(name);
final String transformed;
Printable p = Printable.newPrinter();
if (ui instanceof UiContainerExpr) {
new ElementalTemplatePlugin<>().transformUi(p, (UiExpr) ui);
transformed = p.toSource();
} else {
UiTransformer t = new UiTransformer();
t.setPlugin(new ElementalTemplatePlugin<>());
transformed = ui.toSource(t);
}
assertThat("Expected\n: " + expected+"\n\nActual:\n" + transformed, transformed, equalToIgnoringWhiteSpace(expected));
}
private Node getNode(String name) {
final Node node = compiledByName.get(name);
assertNotNull("No node for name " + name, node);
return node;
}
}