From 7183854fafbc36e0304b1f9e129b0d2cdce4b49e Mon Sep 17 00:00:00 2001
From: casid
Date: Fri, 29 Sep 2023 18:10:31 +0200
Subject: [PATCH 1/7] #278 initial draft of jte modules
---
.../compiler/kotlin/KotlinCodeGenerator.java | 7 +-
.../gg/jte/compiler/TemplateCompiler.java | 62 +++++++++---
.../jte/compiler/java/JavaCodeGenerator.java | 7 +-
.../java/gg/jte/compiler/module/Module.java | 58 +++++++++++
.../compiler/module/ModuleCodeResolver.java | 44 +++++++++
.../gg/jte/compiler/module/ModuleImport.java | 3 +
.../gg/jte/compiler/module/ModuleInfo.java | 6 ++
.../jte/compiler/module/ModuleInfoParser.java | 98 +++++++++++++++++++
.../gg/jte/TemplateEngine_ModulesTest.java | 38 +++++++
.../compiler/module/ModuleInfoParserTest.java | 35 +++++++
.../modules/three-modules/apexcharts/.jteroot | 0
.../three-modules/apexcharts/line-chart.jte | 2 +
.../test/modules/three-modules/app/.jteroot | 2 +
.../test/modules/three-modules/app/page.jte | 1 +
.../test/modules/three-modules/core/.jteroot | 1 +
.../modules/three-modules/core/layout.jte | 6 ++
jte/src/test/modules/two-modules/app/.jteroot | 1 +
jte/src/test/modules/two-modules/app/page.jte | 1 +
.../test/modules/two-modules/core/.jteroot | 1 +
.../two-modules/core/component/css.jte | 2 +
.../test/modules/two-modules/core/layout.jte | 5 +
21 files changed, 363 insertions(+), 17 deletions(-)
create mode 100644 jte/src/main/java/gg/jte/compiler/module/Module.java
create mode 100644 jte/src/main/java/gg/jte/compiler/module/ModuleCodeResolver.java
create mode 100644 jte/src/main/java/gg/jte/compiler/module/ModuleImport.java
create mode 100644 jte/src/main/java/gg/jte/compiler/module/ModuleInfo.java
create mode 100644 jte/src/main/java/gg/jte/compiler/module/ModuleInfoParser.java
create mode 100644 jte/src/test/java/gg/jte/TemplateEngine_ModulesTest.java
create mode 100644 jte/src/test/java/gg/jte/compiler/module/ModuleInfoParserTest.java
create mode 100644 jte/src/test/modules/three-modules/apexcharts/.jteroot
create mode 100644 jte/src/test/modules/three-modules/apexcharts/line-chart.jte
create mode 100644 jte/src/test/modules/three-modules/app/.jteroot
create mode 100644 jte/src/test/modules/three-modules/app/page.jte
create mode 100644 jte/src/test/modules/three-modules/core/.jteroot
create mode 100644 jte/src/test/modules/three-modules/core/layout.jte
create mode 100644 jte/src/test/modules/two-modules/app/.jteroot
create mode 100644 jte/src/test/modules/two-modules/app/page.jte
create mode 100644 jte/src/test/modules/two-modules/core/.jteroot
create mode 100644 jte/src/test/modules/two-modules/core/component/css.jte
create mode 100644 jte/src/test/modules/two-modules/core/layout.jte
diff --git a/jte-kotlin/src/main/java/gg/jte/compiler/kotlin/KotlinCodeGenerator.java b/jte-kotlin/src/main/java/gg/jte/compiler/kotlin/KotlinCodeGenerator.java
index 3eb69a9d..e8e424e5 100644
--- a/jte-kotlin/src/main/java/gg/jte/compiler/kotlin/KotlinCodeGenerator.java
+++ b/jte-kotlin/src/main/java/gg/jte/compiler/kotlin/KotlinCodeGenerator.java
@@ -5,6 +5,7 @@
import gg.jte.TemplateException;
import gg.jte.compiler.*;
import gg.jte.compiler.CodeBuilder.CodeMarker;
+import gg.jte.compiler.module.Module;
import gg.jte.runtime.ClassInfo;
import gg.jte.runtime.Constants;
import gg.jte.runtime.DebugInfo;
@@ -25,6 +26,7 @@ public class KotlinCodeGenerator implements CodeGenerator {
private final CodeBuilder kotlinCode = new CodeBuilder(CodeType.Kotlin);
private final LinkedHashSet classDefinitions;
private final LinkedHashSet templateDependencies;
+ private final Module module;
private final List parameters = new ArrayList<>();
private final List imports = new ArrayList<>();
private final List binaryTextParts = new ArrayList<>();
@@ -35,13 +37,14 @@ public class KotlinCodeGenerator implements CodeGenerator {
private CodeMarker fieldsMarker;
private int attributeCounter;
- public KotlinCodeGenerator(TemplateCompiler compiler, TemplateConfig config, ConcurrentHashMap> paramOrder, ClassInfo classInfo, LinkedHashSet classDefinitions, LinkedHashSet templateDependencies) {
+ public KotlinCodeGenerator(TemplateCompiler compiler, TemplateConfig config, ConcurrentHashMap> paramOrder, ClassInfo classInfo, LinkedHashSet classDefinitions, LinkedHashSet templateDependencies, Module module ) {
this.compiler = compiler;
this.config = config;
this.paramOrder = paramOrder;
this.classInfo = classInfo;
this.classDefinitions = classDefinitions;
this.templateDependencies = templateDependencies;
+ this.module = module;
}
@Override
@@ -426,7 +429,7 @@ public void onForLoopEnd(int depth) {
@Override
public void onTemplateCall(int depth, String name, List params) {
- ClassInfo tagInfo = compiler.generateTemplateCall(name, "kte", classDefinitions, templateDependencies, getCurrentDebugInfo());
+ ClassInfo tagInfo = compiler.generateTemplateCall(name, "kte", classDefinitions, templateDependencies, getCurrentDebugInfo(), module);
writeIndentation(depth);
diff --git a/jte/src/main/java/gg/jte/compiler/TemplateCompiler.java b/jte/src/main/java/gg/jte/compiler/TemplateCompiler.java
index c3fc45c2..a7a71fba 100644
--- a/jte/src/main/java/gg/jte/compiler/TemplateCompiler.java
+++ b/jte/src/main/java/gg/jte/compiler/TemplateCompiler.java
@@ -8,10 +8,15 @@
import gg.jte.compiler.extensionsupport.ExtensionTemplateDescription;
import gg.jte.compiler.java.JavaClassCompiler;
import gg.jte.compiler.java.JavaCodeGenerator;
+import gg.jte.compiler.module.Module;
+import gg.jte.compiler.module.ModuleImport;
+import gg.jte.compiler.module.ModuleInfo;
+import gg.jte.compiler.module.ModuleInfoParser;
import gg.jte.extension.api.JteConfig;
import gg.jte.extension.api.JteExtension;
import gg.jte.extension.api.TemplateDescription;
import gg.jte.output.FileOutput;
+import gg.jte.resolve.DirectoryCodeResolver;
import gg.jte.runtime.*;
import java.io.IOException;
@@ -86,7 +91,8 @@ public List generateAll() {
@Override
public List precompileAll() {
- return precompile(codeResolver.resolveAllTemplateNames());
+ LinkedHashSet classDefinitions = generate(codeResolver.resolveAllTemplateNames(), false);
+ return precompileClasses(classDefinitions);
}
public List precompile(List names) {
@@ -161,12 +167,14 @@ ClassCompiler createCompiler(String extension) {
}
}
- private LinkedHashSet generate(List names, boolean trackChanges) {
+ private LinkedHashSet generate(List names, boolean trackChanges ) {
+ Module module = readModuleInformation("", codeResolver);
+
LinkedHashSet classDefinitions = new LinkedHashSet<>();
for (String name : names) {
LinkedHashSet dependencies = initTemplateDependencies(name);
- ClassInfo templateInfo = generateTemplateCall(name, classDefinitions, dependencies, null);
+ ClassInfo templateInfo = generateTemplateCall(name, classDefinitions, dependencies, null, module);
templateDependencies.put(name, dependencies);
templateByClassName.put(templateInfo.name, templateInfo);
@@ -223,21 +231,44 @@ private LinkedHashSet generate(List names, boolean trac
return classDefinitions;
}
+ private Module readModuleInformation(String alias, CodeResolver codeResolver) {
+ String jteRootContent = codeResolver.resolve(".jteroot");
+ if (jteRootContent == null) {
+ return new Module(alias, codeResolver, Map.of());
+ }
+
+ if (!(codeResolver instanceof DirectoryCodeResolver directoryCodeResolver)) {
+ return new Module(alias, codeResolver, Map.of());
+ }
+
+ ModuleInfo moduleInfo = ModuleInfoParser.parse(jteRootContent);
+ Map children = new LinkedHashMap<>();
+
+ for ( ModuleImport moduleImport : moduleInfo.imports() ) {
+ DirectoryCodeResolver moduleDirectoryResolver = new DirectoryCodeResolver(directoryCodeResolver.getRoot().resolve(moduleImport.from()));
+ children.put(moduleImport.alias(), readModuleInformation(moduleImport.alias(), moduleDirectoryResolver));
+ }
+
+ return new Module(alias, codeResolver, children);
+ }
+
private LinkedHashSet initTemplateDependencies(String name) {
LinkedHashSet templateDependencies = new LinkedHashSet<>();
templateDependencies.add(new TemplateDependency(name, codeResolver.getLastModified(name)));
return templateDependencies;
}
- public ClassInfo generateTemplateCall(String simpleName, String extension, LinkedHashSet classDefinitions, LinkedHashSet templateDependencies, DebugInfo debugInfo) {
+ public ClassInfo generateTemplateCall(String simpleName, String extension, LinkedHashSet classDefinitions, LinkedHashSet templateDependencies, DebugInfo debugInfo, Module module) {
String name = resolveTemplateName(simpleName, extension);
try {
- return generateTemplateCall(name, classDefinitions, templateDependencies, debugInfo);
+ return generateTemplateCall(name, classDefinitions, templateDependencies, debugInfo, module);
} catch (TemplateNotFoundException e) {
String alternativeName = resolveTemplateName(simpleName, "jte".equals(extension) ? "kte" : "jte");
+ Module templateModule = module.resolve(name);
+ CodeResolver codeResolver = templateModule.getCodeResolver();
if (codeResolver.exists(alternativeName)) {
- return generateTemplateCall(alternativeName, classDefinitions, templateDependencies, debugInfo);
+ return generateTemplateCall(alternativeName, classDefinitions, templateDependencies, debugInfo, module);
} else {
throw e;
}
@@ -248,7 +279,10 @@ private String resolveTemplateName(String simpleName, String extension) {
return simpleName.replace('.', '/') + "." + extension;
}
- public ClassInfo generateTemplateCall(String name, LinkedHashSet classDefinitions, LinkedHashSet templateDependencies, DebugInfo debugInfo) {
+ public ClassInfo generateTemplateCall(String name, LinkedHashSet classDefinitions, LinkedHashSet templateDependencies, DebugInfo debugInfo, Module module) {
+ Module templateModule = module.resolve(name);
+ CodeResolver codeResolver = templateModule.getCodeResolver();
+
templateDependencies.add(new TemplateDependency(name, codeResolver.getLastModified(name)));
ClassInfo classInfo = new ClassInfo(name, config.packageName);
@@ -257,11 +291,11 @@ public ClassInfo generateTemplateCall(String name, LinkedHashSet classDefinitions, LinkedHashSet templateDependencies) {
+ private CodeGenerator createCodeGenerator(ClassInfo classInfo, LinkedHashSet classDefinitions, LinkedHashSet templateDependencies,
+ Module module ) {
if ("kte".equals(classInfo.extension)) {
try {
Class> compilerClass = Class.forName("gg.jte.compiler.kotlin.KotlinCodeGenerator");
- return (CodeGenerator)compilerClass.getConstructor(TemplateCompiler.class, TemplateConfig.class, ConcurrentHashMap.class, ClassInfo.class, LinkedHashSet.class, LinkedHashSet.class).newInstance(this, this.config, paramOrder, classInfo, classDefinitions, templateDependencies);
+ return (CodeGenerator)compilerClass.getConstructor(TemplateCompiler.class, TemplateConfig.class, ConcurrentHashMap.class, ClassInfo.class, LinkedHashSet.class, LinkedHashSet.class, Module.class).newInstance(this, this.config, paramOrder, classInfo, classDefinitions, templateDependencies, module);
} catch (Exception e) {
throw new TemplateException("Failed to create kotlin generator. To handle .kte files, you need to add gg.jte:jte-kotlin to your project.", e);
}
} else {
- return new JavaCodeGenerator(this, this.config, paramOrder, classInfo, classDefinitions, templateDependencies);
+ return new JavaCodeGenerator(this, this.config, paramOrder, classInfo, classDefinitions, templateDependencies, module);
}
}
- private String resolveCode(String name, DebugInfo debugInfo) {
+ private String resolveCode(CodeResolver codeResolver, String name, DebugInfo debugInfo) {
try {
return codeResolver.resolveRequired(name);
} catch (TemplateNotFoundException e) {
@@ -341,4 +376,5 @@ private JteExtension loadExtension(Map.Entry> extens
throw new TemplateException("Failed to load extension " + extensionSettings.getKey(), e);
}
}
+
}
diff --git a/jte/src/main/java/gg/jte/compiler/java/JavaCodeGenerator.java b/jte/src/main/java/gg/jte/compiler/java/JavaCodeGenerator.java
index eba67c06..93d35a92 100644
--- a/jte/src/main/java/gg/jte/compiler/java/JavaCodeGenerator.java
+++ b/jte/src/main/java/gg/jte/compiler/java/JavaCodeGenerator.java
@@ -5,6 +5,7 @@
import gg.jte.TemplateException;
import gg.jte.compiler.*;
import gg.jte.compiler.CodeBuilder.CodeMarker;
+import gg.jte.compiler.module.Module;
import gg.jte.runtime.ClassInfo;
import gg.jte.runtime.Constants;
import gg.jte.runtime.DebugInfo;
@@ -24,6 +25,7 @@ public class JavaCodeGenerator implements CodeGenerator {
private final CodeBuilder javaCode = new CodeBuilder(CodeType.Java);
private final LinkedHashSet classDefinitions;
private final LinkedHashSet templateDependencies;
+ private final Module module;
private final List parameters = new ArrayList<>();
private final List imports = new ArrayList<>();
private final List binaryTextParts = new ArrayList<>();
@@ -34,13 +36,14 @@ public class JavaCodeGenerator implements CodeGenerator {
private CodeMarker fieldsMarker;
private int attributeCounter;
- public JavaCodeGenerator(TemplateCompiler compiler, TemplateConfig config, ConcurrentHashMap> paramOrder, ClassInfo classInfo, LinkedHashSet classDefinitions, LinkedHashSet templateDependencies) {
+ public JavaCodeGenerator(TemplateCompiler compiler, TemplateConfig config, ConcurrentHashMap> paramOrder, ClassInfo classInfo, LinkedHashSet classDefinitions, LinkedHashSet templateDependencies, Module module ) {
this.compiler = compiler;
this.config = config;
this.paramOrder = paramOrder;
this.classInfo = classInfo;
this.classDefinitions = classDefinitions;
this.templateDependencies = templateDependencies;
+ this.module = module;
}
@Override
@@ -420,7 +423,7 @@ public void onForLoopEnd(int depth) {
@Override
public void onTemplateCall(int depth, String name, List params) {
- ClassInfo tagInfo = compiler.generateTemplateCall(name, "jte", classDefinitions, templateDependencies, getCurrentDebugInfo());
+ ClassInfo tagInfo = compiler.generateTemplateCall(name, "jte", classDefinitions, templateDependencies, getCurrentDebugInfo(), module);
writeIndentation(depth);
diff --git a/jte/src/main/java/gg/jte/compiler/module/Module.java b/jte/src/main/java/gg/jte/compiler/module/Module.java
new file mode 100644
index 00000000..db58d687
--- /dev/null
+++ b/jte/src/main/java/gg/jte/compiler/module/Module.java
@@ -0,0 +1,58 @@
+package gg.jte.compiler.module;
+
+import java.util.Map;
+
+import gg.jte.CodeResolver;
+
+
+public final class Module {
+
+ public static String getModuleAlias(String name) {
+ int index = name.indexOf('/');
+ if (index == -1) {
+ return null;
+ }
+
+ return name.substring(0, index);
+ }
+
+ private final String alias;
+ private final CodeResolver codeResolver;
+ private final Map children;
+
+ public Module( String alias, CodeResolver codeResolver, Map children ) {
+ this.alias = alias;
+ this.codeResolver = isRoot() ? codeResolver : new ModuleCodeResolver(alias, codeResolver);
+ this.children = children;
+ }
+
+ public Module resolve(String name) {
+ if (children.isEmpty()) {
+ return this;
+ }
+
+ String moduleAlias = getModuleAlias(name);
+ if (moduleAlias == null) {
+ return this;
+ }
+
+ Module result = children.get(moduleAlias);
+ if (result == null) {
+ return this;
+ }
+
+ return result;
+ }
+
+ public boolean isRoot() {
+ return alias.isEmpty();
+ }
+
+ public String getAlias() {
+ return alias;
+ }
+
+ public CodeResolver getCodeResolver() {
+ return codeResolver;
+ }
+}
diff --git a/jte/src/main/java/gg/jte/compiler/module/ModuleCodeResolver.java b/jte/src/main/java/gg/jte/compiler/module/ModuleCodeResolver.java
new file mode 100644
index 00000000..a8e88f5e
--- /dev/null
+++ b/jte/src/main/java/gg/jte/compiler/module/ModuleCodeResolver.java
@@ -0,0 +1,44 @@
+package gg.jte.compiler.module;
+
+import gg.jte.CodeResolver;
+import gg.jte.TemplateNotFoundException;
+
+
+public class ModuleCodeResolver implements CodeResolver {
+
+ private final CodeResolver codeResolver;
+ private final String aliasSlash;
+
+ public ModuleCodeResolver( String alias, CodeResolver codeResolver ) {
+ this.codeResolver = codeResolver;
+ this.aliasSlash = alias + "/";
+ }
+
+ @Override
+ public String resolve( String name ) {
+ return codeResolver.resolve(removeAlias(name));
+ }
+
+ @Override
+ public String resolveRequired( String name ) throws TemplateNotFoundException {
+ return codeResolver.resolveRequired(removeAlias(name));
+ }
+
+ @Override
+ public long getLastModified( String name ) {
+ return codeResolver.getLastModified(removeAlias(name));
+ }
+
+ @Override
+ public boolean exists( String name ) {
+ return codeResolver.exists(removeAlias(name));
+ }
+
+ private String removeAlias(String name) {
+ if (name.startsWith(aliasSlash)) {
+ return name.substring(aliasSlash.length());
+ }
+
+ return name;
+ }
+}
diff --git a/jte/src/main/java/gg/jte/compiler/module/ModuleImport.java b/jte/src/main/java/gg/jte/compiler/module/ModuleImport.java
new file mode 100644
index 00000000..8402a5bf
--- /dev/null
+++ b/jte/src/main/java/gg/jte/compiler/module/ModuleImport.java
@@ -0,0 +1,3 @@
+package gg.jte.compiler.module;
+
+public record ModuleImport(String alias, String from) {}
diff --git a/jte/src/main/java/gg/jte/compiler/module/ModuleInfo.java b/jte/src/main/java/gg/jte/compiler/module/ModuleInfo.java
new file mode 100644
index 00000000..4d82fe1e
--- /dev/null
+++ b/jte/src/main/java/gg/jte/compiler/module/ModuleInfo.java
@@ -0,0 +1,6 @@
+package gg.jte.compiler.module;
+
+import java.util.List;
+
+
+public record ModuleInfo(List imports) {}
diff --git a/jte/src/main/java/gg/jte/compiler/module/ModuleInfoParser.java b/jte/src/main/java/gg/jte/compiler/module/ModuleInfoParser.java
new file mode 100644
index 00000000..1efd5e27
--- /dev/null
+++ b/jte/src/main/java/gg/jte/compiler/module/ModuleInfoParser.java
@@ -0,0 +1,98 @@
+package gg.jte.compiler.module;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+
+
+public class ModuleInfoParser {
+
+ public static ModuleInfo parse(String moduleInfo) {
+ return new ModuleInfoParser(moduleInfo).parse();
+ }
+
+ private final String moduleInfo;
+ private final int startIndex;
+ private final int endIndex;
+
+ private final Deque stack = new ArrayDeque<>();
+
+ private int i;
+ private int lastIndex = 0;
+ private Mode currentMode;
+
+ private ModuleInfoParser( String moduleInfo ) {
+ this.moduleInfo = moduleInfo;
+
+ this.startIndex = 0;
+ this.endIndex = moduleInfo.length();
+ }
+
+ private ModuleInfo parse() {
+ ModuleInfo result = new ModuleInfo(new ArrayList<>());
+
+ push(Mode.Root);
+
+ for ( i = startIndex; i < endIndex; ++i) {
+ char currentChar = moduleInfo.charAt(i);
+
+ if (currentMode == Mode.Root && regionMatches("@import")) {
+ push(new ImportMode());
+ lastIndex = i + 1;
+ } else if (currentMode instanceof ImportMode importMode) {
+ if (regionMatches("from")) {
+ importMode.alias = extractFromLastIndex(-4).trim();
+ } else if ( currentChar == '\n' || i == endIndex - 1) {
+ importMode.from = extractFromLastIndex(1).trim();
+ result.imports().add(new ModuleImport(importMode.alias, importMode.from));
+ pop();
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private String extractFromLastIndex(int offset) {
+ String result = moduleInfo.substring(lastIndex, i + offset);
+ lastIndex = i + 1;
+ return result;
+ }
+
+ private void push( Mode mode) {
+ currentMode = mode;
+ stack.push(currentMode);
+ }
+
+ private void pop() {
+ stack.pop();
+ currentMode = stack.peek();
+ }
+
+ private boolean regionMatches(String s) {
+ return moduleInfo.regionMatches(i - s.length() + 1, s, 0, s.length());
+ }
+
+ private interface Mode {
+ Mode Root = new StatelessMode("Root");
+ }
+
+ private static class StatelessMode implements Mode {
+
+ private final String debugName;
+
+ public StatelessMode( String debugName ) {
+ this.debugName = debugName;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "[" + debugName + "]";
+ }
+ }
+
+ private static class ImportMode implements Mode {
+ String alias;
+ String from;
+ }
+}
diff --git a/jte/src/test/java/gg/jte/TemplateEngine_ModulesTest.java b/jte/src/test/java/gg/jte/TemplateEngine_ModulesTest.java
new file mode 100644
index 00000000..74570823
--- /dev/null
+++ b/jte/src/test/java/gg/jte/TemplateEngine_ModulesTest.java
@@ -0,0 +1,38 @@
+package gg.jte;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.nio.file.Path;
+
+import org.junit.jupiter.api.Test;
+
+import gg.jte.output.StringOutput;
+import gg.jte.resolve.DirectoryCodeResolver;
+
+
+public class TemplateEngine_ModulesTest {
+
+ @Test
+ void twoModules() {
+ DirectoryCodeResolver codeResolver = new DirectoryCodeResolver(Path.of("src/test/modules/two-modules/app"));
+ TemplateEngine templateEngine = TemplateEngine.create(codeResolver, ContentType.Html);
+
+ StringOutput output = new StringOutput();
+ templateEngine.render("page.jte", null, output);
+
+ assertThat(output.toString().trim()).isEqualToNormalizingNewlines("\nApp Page
");
+ }
+
+ @Test
+ void threeModules() {
+ DirectoryCodeResolver codeResolver = new DirectoryCodeResolver(Path.of("src/test/modules/three-modules/app"));
+ TemplateEngine templateEngine = TemplateEngine.create(codeResolver, ContentType.Html);
+
+ StringOutput output = new StringOutput();
+ templateEngine.render("page.jte", null, output);
+
+ assertThat(output.toString().trim()).isEqualToNormalizingNewlines("line chart (app)
\nline chart (core)");
+ }
+
+ // TODO adjust precompileAll() and generateAll() to iterate over all module files as well!
+}
diff --git a/jte/src/test/java/gg/jte/compiler/module/ModuleInfoParserTest.java b/jte/src/test/java/gg/jte/compiler/module/ModuleInfoParserTest.java
new file mode 100644
index 00000000..f31bdb17
--- /dev/null
+++ b/jte/src/test/java/gg/jte/compiler/module/ModuleInfoParserTest.java
@@ -0,0 +1,35 @@
+package gg.jte.compiler.module;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.Test;
+
+
+class ModuleInfoParserTest {
+
+ @Test
+ void empty() {
+ ModuleInfo moduleInfo = ModuleInfoParser.parse("");
+ assertThat(moduleInfo.imports()).isEmpty();
+ }
+
+ @Test
+ void oneModule() {
+ ModuleInfo moduleInfo = ModuleInfoParser.parse("@import core from ../core");
+
+ assertThat(moduleInfo.imports()).hasSize(1);
+ assertThat(moduleInfo.imports().get(0).alias()).isEqualTo("core");
+ assertThat(moduleInfo.imports().get(0).from()).isEqualTo("../core");
+ }
+
+ @Test
+ void twoModules() {
+ ModuleInfo moduleInfo = ModuleInfoParser.parse("@import foo from ../foo\n@import bar from ../bar");
+
+ assertThat(moduleInfo.imports()).hasSize(2);
+ assertThat(moduleInfo.imports().get(0).alias()).isEqualTo("foo");
+ assertThat(moduleInfo.imports().get(0).from()).isEqualTo("../foo");
+ assertThat(moduleInfo.imports().get(1).alias()).isEqualTo("bar");
+ assertThat(moduleInfo.imports().get(1).from()).isEqualTo("../bar");
+ }
+}
\ No newline at end of file
diff --git a/jte/src/test/modules/three-modules/apexcharts/.jteroot b/jte/src/test/modules/three-modules/apexcharts/.jteroot
new file mode 100644
index 00000000..e69de29b
diff --git a/jte/src/test/modules/three-modules/apexcharts/line-chart.jte b/jte/src/test/modules/three-modules/apexcharts/line-chart.jte
new file mode 100644
index 00000000..6ac3afba
--- /dev/null
+++ b/jte/src/test/modules/three-modules/apexcharts/line-chart.jte
@@ -0,0 +1,2 @@
+@param String name
+line chart (${name})
\ No newline at end of file
diff --git a/jte/src/test/modules/three-modules/app/.jteroot b/jte/src/test/modules/three-modules/app/.jteroot
new file mode 100644
index 00000000..9f3d0dfc
--- /dev/null
+++ b/jte/src/test/modules/three-modules/app/.jteroot
@@ -0,0 +1,2 @@
+@import core from ../core
+@import charts from ../apexcharts
\ No newline at end of file
diff --git a/jte/src/test/modules/three-modules/app/page.jte b/jte/src/test/modules/three-modules/app/page.jte
new file mode 100644
index 00000000..17292d86
--- /dev/null
+++ b/jte/src/test/modules/three-modules/app/page.jte
@@ -0,0 +1 @@
+@template.core.layout(content = @`@template.charts.line-chart("app")`)
\ No newline at end of file
diff --git a/jte/src/test/modules/three-modules/core/.jteroot b/jte/src/test/modules/three-modules/core/.jteroot
new file mode 100644
index 00000000..ae389598
--- /dev/null
+++ b/jte/src/test/modules/three-modules/core/.jteroot
@@ -0,0 +1 @@
+@import apexcharts from ../apexcharts
\ No newline at end of file
diff --git a/jte/src/test/modules/three-modules/core/layout.jte b/jte/src/test/modules/three-modules/core/layout.jte
new file mode 100644
index 00000000..ed7fc09a
--- /dev/null
+++ b/jte/src/test/modules/three-modules/core/layout.jte
@@ -0,0 +1,6 @@
+@import gg.jte.Content
+
+@param Content content
+
+${content}
+@template.apexcharts.line-chart("core")
\ No newline at end of file
diff --git a/jte/src/test/modules/two-modules/app/.jteroot b/jte/src/test/modules/two-modules/app/.jteroot
new file mode 100644
index 00000000..7403868b
--- /dev/null
+++ b/jte/src/test/modules/two-modules/app/.jteroot
@@ -0,0 +1 @@
+@import core from ../core
\ No newline at end of file
diff --git a/jte/src/test/modules/two-modules/app/page.jte b/jte/src/test/modules/two-modules/app/page.jte
new file mode 100644
index 00000000..60311a1e
--- /dev/null
+++ b/jte/src/test/modules/two-modules/app/page.jte
@@ -0,0 +1 @@
+@template.core.layout(content = @`App Page`)
\ No newline at end of file
diff --git a/jte/src/test/modules/two-modules/core/.jteroot b/jte/src/test/modules/two-modules/core/.jteroot
new file mode 100644
index 00000000..ae389598
--- /dev/null
+++ b/jte/src/test/modules/two-modules/core/.jteroot
@@ -0,0 +1 @@
+@import apexcharts from ../apexcharts
\ No newline at end of file
diff --git a/jte/src/test/modules/two-modules/core/component/css.jte b/jte/src/test/modules/two-modules/core/component/css.jte
new file mode 100644
index 00000000..8b8b072d
--- /dev/null
+++ b/jte/src/test/modules/two-modules/core/component/css.jte
@@ -0,0 +1,2 @@
+@param String css
+
diff --git a/jte/src/test/modules/two-modules/core/layout.jte b/jte/src/test/modules/two-modules/core/layout.jte
new file mode 100644
index 00000000..f30f4db6
--- /dev/null
+++ b/jte/src/test/modules/two-modules/core/layout.jte
@@ -0,0 +1,5 @@
+@import gg.jte.Content
+
+@param Content content
+
+@template.component.css(css = "important")${content}
\ No newline at end of file
From 9edd8c9266334062cddac6f0ea28f654bfc2f86c Mon Sep 17 00:00:00 2001
From: Andreas Hager
Date: Sat, 30 Sep 2023 06:41:00 +0200
Subject: [PATCH 2/7] #278 add more module test cases
---
.../gg/jte/TemplateEngine_ModulesTest.java | 40 ++++++++++++++++++-
.../modules/empty-top-level-module/.jteroot | 3 ++
.../apexcharts/.jteroot | 0
.../apexcharts/line-chart.jte | 0
.../empty-top-level-module/checkout/.jteroot | 2 +
.../empty-top-level-module/checkout/page.jte | 1 +
.../core/.jteroot | 0
.../core/component/css.jte | 2 +
.../empty-top-level-module/core/layout.jte | 6 +++
.../apexcharts/.jteroot | 0
.../apexcharts/line-chart.jte | 2 +
.../app/.jteroot | 0
.../app/page.jte | 0
.../core/.jteroot | 1 +
.../core/layout.jte | 0
.../apexcharts/.jteroot | 0
.../apexcharts/line-chart.jte | 2 +
.../three-modules-same-alias/app/.jteroot | 2 +
.../three-modules-same-alias/app/page.jte | 1 +
.../three-modules-same-alias/core/.jteroot | 1 +
.../three-modules-same-alias/core/layout.jte | 6 +++
.../modules/two-modules-cycle/app/.jteroot | 1 +
.../modules/two-modules-cycle/app/page.jte | 1 +
.../modules/two-modules-cycle/core/.jteroot | 1 +
.../modules/two-modules-cycle/core/layout.jte | 5 +++
.../test/modules/two-modules/core/.jteroot | 1 -
26 files changed, 75 insertions(+), 3 deletions(-)
create mode 100644 jte/src/test/modules/empty-top-level-module/.jteroot
rename jte/src/test/modules/{three-modules => empty-top-level-module}/apexcharts/.jteroot (100%)
rename jte/src/test/modules/{three-modules => empty-top-level-module}/apexcharts/line-chart.jte (100%)
create mode 100644 jte/src/test/modules/empty-top-level-module/checkout/.jteroot
create mode 100644 jte/src/test/modules/empty-top-level-module/checkout/page.jte
rename jte/src/test/modules/{three-modules => empty-top-level-module}/core/.jteroot (100%)
create mode 100644 jte/src/test/modules/empty-top-level-module/core/component/css.jte
create mode 100644 jte/src/test/modules/empty-top-level-module/core/layout.jte
create mode 100644 jte/src/test/modules/three-modules-different-alias/apexcharts/.jteroot
create mode 100644 jte/src/test/modules/three-modules-different-alias/apexcharts/line-chart.jte
rename jte/src/test/modules/{three-modules => three-modules-different-alias}/app/.jteroot (100%)
rename jte/src/test/modules/{three-modules => three-modules-different-alias}/app/page.jte (100%)
create mode 100644 jte/src/test/modules/three-modules-different-alias/core/.jteroot
rename jte/src/test/modules/{three-modules => three-modules-different-alias}/core/layout.jte (100%)
create mode 100644 jte/src/test/modules/three-modules-same-alias/apexcharts/.jteroot
create mode 100644 jte/src/test/modules/three-modules-same-alias/apexcharts/line-chart.jte
create mode 100644 jte/src/test/modules/three-modules-same-alias/app/.jteroot
create mode 100644 jte/src/test/modules/three-modules-same-alias/app/page.jte
create mode 100644 jte/src/test/modules/three-modules-same-alias/core/.jteroot
create mode 100644 jte/src/test/modules/three-modules-same-alias/core/layout.jte
create mode 100644 jte/src/test/modules/two-modules-cycle/app/.jteroot
create mode 100644 jte/src/test/modules/two-modules-cycle/app/page.jte
create mode 100644 jte/src/test/modules/two-modules-cycle/core/.jteroot
create mode 100644 jte/src/test/modules/two-modules-cycle/core/layout.jte
diff --git a/jte/src/test/java/gg/jte/TemplateEngine_ModulesTest.java b/jte/src/test/java/gg/jte/TemplateEngine_ModulesTest.java
index 74570823..a7f8c2a3 100644
--- a/jte/src/test/java/gg/jte/TemplateEngine_ModulesTest.java
+++ b/jte/src/test/java/gg/jte/TemplateEngine_ModulesTest.java
@@ -1,6 +1,7 @@
package gg.jte;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.catchThrowable;
import java.nio.file.Path;
@@ -24,8 +25,29 @@ void twoModules() {
}
@Test
- void threeModules() {
- DirectoryCodeResolver codeResolver = new DirectoryCodeResolver(Path.of("src/test/modules/three-modules/app"));
+ void twoModulesCycle() {
+ DirectoryCodeResolver codeResolver = new DirectoryCodeResolver(Path.of("src/test/modules/two-modules-cycle/app"));
+ TemplateEngine templateEngine = TemplateEngine.create(codeResolver, ContentType.Html);
+
+ Throwable throwable = catchThrowable(() -> templateEngine.render("page.jte", null, new StringOutput()));
+
+ assertThat(throwable).isInstanceOf(StackOverflowError.class); // TODO better error message :-D
+ }
+
+ @Test
+ void threeModulesDifferentAlias() {
+ DirectoryCodeResolver codeResolver = new DirectoryCodeResolver(Path.of("src/test/modules/three-modules-different-alias/app"));
+ TemplateEngine templateEngine = TemplateEngine.create(codeResolver, ContentType.Html);
+
+ StringOutput output = new StringOutput();
+ templateEngine.render("page.jte", null, output);
+
+ assertThat(output.toString().trim()).isEqualToNormalizingNewlines("line chart (app)
\nline chart (core)");
+ }
+
+ @Test
+ void threeModulesSameAlias() {
+ DirectoryCodeResolver codeResolver = new DirectoryCodeResolver(Path.of("src/test/modules/three-modules-same-alias/app"));
TemplateEngine templateEngine = TemplateEngine.create(codeResolver, ContentType.Html);
StringOutput output = new StringOutput();
@@ -34,5 +56,19 @@ void threeModules() {
assertThat(output.toString().trim()).isEqualToNormalizingNewlines("line chart (app)
\nline chart (core)");
}
+ @Test
+ void emptyTopLevelModule() {
+ DirectoryCodeResolver codeResolver = new DirectoryCodeResolver(Path.of("src/test/modules/empty-top-level-module"));
+ TemplateEngine templateEngine = TemplateEngine.create(codeResolver, ContentType.Html);
+
+ StringOutput output = new StringOutput();
+ templateEngine.render("checkout/page.jte", null, output);
+
+ assertThat(output.toString().trim()).isEqualToNormalizingNewlines("""
+
+ line chart (checkout)
+ line chart (core)""");
+ }
+
// TODO adjust precompileAll() and generateAll() to iterate over all module files as well!
}
diff --git a/jte/src/test/modules/empty-top-level-module/.jteroot b/jte/src/test/modules/empty-top-level-module/.jteroot
new file mode 100644
index 00000000..d65d1049
--- /dev/null
+++ b/jte/src/test/modules/empty-top-level-module/.jteroot
@@ -0,0 +1,3 @@
+@import apexcharts from apexcharts
+@import checkout from checkout
+@import core from core
\ No newline at end of file
diff --git a/jte/src/test/modules/three-modules/apexcharts/.jteroot b/jte/src/test/modules/empty-top-level-module/apexcharts/.jteroot
similarity index 100%
rename from jte/src/test/modules/three-modules/apexcharts/.jteroot
rename to jte/src/test/modules/empty-top-level-module/apexcharts/.jteroot
diff --git a/jte/src/test/modules/three-modules/apexcharts/line-chart.jte b/jte/src/test/modules/empty-top-level-module/apexcharts/line-chart.jte
similarity index 100%
rename from jte/src/test/modules/three-modules/apexcharts/line-chart.jte
rename to jte/src/test/modules/empty-top-level-module/apexcharts/line-chart.jte
diff --git a/jte/src/test/modules/empty-top-level-module/checkout/.jteroot b/jte/src/test/modules/empty-top-level-module/checkout/.jteroot
new file mode 100644
index 00000000..a921e030
--- /dev/null
+++ b/jte/src/test/modules/empty-top-level-module/checkout/.jteroot
@@ -0,0 +1,2 @@
+@import core from ../core
+@import apexcharts from ../apexcharts
\ No newline at end of file
diff --git a/jte/src/test/modules/empty-top-level-module/checkout/page.jte b/jte/src/test/modules/empty-top-level-module/checkout/page.jte
new file mode 100644
index 00000000..7f0746f3
--- /dev/null
+++ b/jte/src/test/modules/empty-top-level-module/checkout/page.jte
@@ -0,0 +1 @@
+@template.core.layout(content = @`@template.apexcharts.line-chart("checkout")`)
\ No newline at end of file
diff --git a/jte/src/test/modules/three-modules/core/.jteroot b/jte/src/test/modules/empty-top-level-module/core/.jteroot
similarity index 100%
rename from jte/src/test/modules/three-modules/core/.jteroot
rename to jte/src/test/modules/empty-top-level-module/core/.jteroot
diff --git a/jte/src/test/modules/empty-top-level-module/core/component/css.jte b/jte/src/test/modules/empty-top-level-module/core/component/css.jte
new file mode 100644
index 00000000..8b8b072d
--- /dev/null
+++ b/jte/src/test/modules/empty-top-level-module/core/component/css.jte
@@ -0,0 +1,2 @@
+@param String css
+
diff --git a/jte/src/test/modules/empty-top-level-module/core/layout.jte b/jte/src/test/modules/empty-top-level-module/core/layout.jte
new file mode 100644
index 00000000..39021d78
--- /dev/null
+++ b/jte/src/test/modules/empty-top-level-module/core/layout.jte
@@ -0,0 +1,6 @@
+@import gg.jte.Content
+
+@param Content content
+
+@template.component.css(css = "important")${content}
+@template.apexcharts.line-chart("core")
\ No newline at end of file
diff --git a/jte/src/test/modules/three-modules-different-alias/apexcharts/.jteroot b/jte/src/test/modules/three-modules-different-alias/apexcharts/.jteroot
new file mode 100644
index 00000000..e69de29b
diff --git a/jte/src/test/modules/three-modules-different-alias/apexcharts/line-chart.jte b/jte/src/test/modules/three-modules-different-alias/apexcharts/line-chart.jte
new file mode 100644
index 00000000..6ac3afba
--- /dev/null
+++ b/jte/src/test/modules/three-modules-different-alias/apexcharts/line-chart.jte
@@ -0,0 +1,2 @@
+@param String name
+line chart (${name})
\ No newline at end of file
diff --git a/jte/src/test/modules/three-modules/app/.jteroot b/jte/src/test/modules/three-modules-different-alias/app/.jteroot
similarity index 100%
rename from jte/src/test/modules/three-modules/app/.jteroot
rename to jte/src/test/modules/three-modules-different-alias/app/.jteroot
diff --git a/jte/src/test/modules/three-modules/app/page.jte b/jte/src/test/modules/three-modules-different-alias/app/page.jte
similarity index 100%
rename from jte/src/test/modules/three-modules/app/page.jte
rename to jte/src/test/modules/three-modules-different-alias/app/page.jte
diff --git a/jte/src/test/modules/three-modules-different-alias/core/.jteroot b/jte/src/test/modules/three-modules-different-alias/core/.jteroot
new file mode 100644
index 00000000..ae389598
--- /dev/null
+++ b/jte/src/test/modules/three-modules-different-alias/core/.jteroot
@@ -0,0 +1 @@
+@import apexcharts from ../apexcharts
\ No newline at end of file
diff --git a/jte/src/test/modules/three-modules/core/layout.jte b/jte/src/test/modules/three-modules-different-alias/core/layout.jte
similarity index 100%
rename from jte/src/test/modules/three-modules/core/layout.jte
rename to jte/src/test/modules/three-modules-different-alias/core/layout.jte
diff --git a/jte/src/test/modules/three-modules-same-alias/apexcharts/.jteroot b/jte/src/test/modules/three-modules-same-alias/apexcharts/.jteroot
new file mode 100644
index 00000000..e69de29b
diff --git a/jte/src/test/modules/three-modules-same-alias/apexcharts/line-chart.jte b/jte/src/test/modules/three-modules-same-alias/apexcharts/line-chart.jte
new file mode 100644
index 00000000..6ac3afba
--- /dev/null
+++ b/jte/src/test/modules/three-modules-same-alias/apexcharts/line-chart.jte
@@ -0,0 +1,2 @@
+@param String name
+line chart (${name})
\ No newline at end of file
diff --git a/jte/src/test/modules/three-modules-same-alias/app/.jteroot b/jte/src/test/modules/three-modules-same-alias/app/.jteroot
new file mode 100644
index 00000000..a921e030
--- /dev/null
+++ b/jte/src/test/modules/three-modules-same-alias/app/.jteroot
@@ -0,0 +1,2 @@
+@import core from ../core
+@import apexcharts from ../apexcharts
\ No newline at end of file
diff --git a/jte/src/test/modules/three-modules-same-alias/app/page.jte b/jte/src/test/modules/three-modules-same-alias/app/page.jte
new file mode 100644
index 00000000..2b5ec381
--- /dev/null
+++ b/jte/src/test/modules/three-modules-same-alias/app/page.jte
@@ -0,0 +1 @@
+@template.core.layout(content = @`@template.apexcharts.line-chart("app")`)
\ No newline at end of file
diff --git a/jte/src/test/modules/three-modules-same-alias/core/.jteroot b/jte/src/test/modules/three-modules-same-alias/core/.jteroot
new file mode 100644
index 00000000..ae389598
--- /dev/null
+++ b/jte/src/test/modules/three-modules-same-alias/core/.jteroot
@@ -0,0 +1 @@
+@import apexcharts from ../apexcharts
\ No newline at end of file
diff --git a/jte/src/test/modules/three-modules-same-alias/core/layout.jte b/jte/src/test/modules/three-modules-same-alias/core/layout.jte
new file mode 100644
index 00000000..ed7fc09a
--- /dev/null
+++ b/jte/src/test/modules/three-modules-same-alias/core/layout.jte
@@ -0,0 +1,6 @@
+@import gg.jte.Content
+
+@param Content content
+
+${content}
+@template.apexcharts.line-chart("core")
\ No newline at end of file
diff --git a/jte/src/test/modules/two-modules-cycle/app/.jteroot b/jte/src/test/modules/two-modules-cycle/app/.jteroot
new file mode 100644
index 00000000..7403868b
--- /dev/null
+++ b/jte/src/test/modules/two-modules-cycle/app/.jteroot
@@ -0,0 +1 @@
+@import core from ../core
\ No newline at end of file
diff --git a/jte/src/test/modules/two-modules-cycle/app/page.jte b/jte/src/test/modules/two-modules-cycle/app/page.jte
new file mode 100644
index 00000000..60311a1e
--- /dev/null
+++ b/jte/src/test/modules/two-modules-cycle/app/page.jte
@@ -0,0 +1 @@
+@template.core.layout(content = @`App Page`)
\ No newline at end of file
diff --git a/jte/src/test/modules/two-modules-cycle/core/.jteroot b/jte/src/test/modules/two-modules-cycle/core/.jteroot
new file mode 100644
index 00000000..8e505a42
--- /dev/null
+++ b/jte/src/test/modules/two-modules-cycle/core/.jteroot
@@ -0,0 +1 @@
+@import app from ../app
\ No newline at end of file
diff --git a/jte/src/test/modules/two-modules-cycle/core/layout.jte b/jte/src/test/modules/two-modules-cycle/core/layout.jte
new file mode 100644
index 00000000..87855a03
--- /dev/null
+++ b/jte/src/test/modules/two-modules-cycle/core/layout.jte
@@ -0,0 +1,5 @@
+@import gg.jte.Content
+
+@param Content content
+
+${content}
\ No newline at end of file
diff --git a/jte/src/test/modules/two-modules/core/.jteroot b/jte/src/test/modules/two-modules/core/.jteroot
index ae389598..e69de29b 100644
--- a/jte/src/test/modules/two-modules/core/.jteroot
+++ b/jte/src/test/modules/two-modules/core/.jteroot
@@ -1 +0,0 @@
-@import apexcharts from ../apexcharts
\ No newline at end of file
From d940f929c8c6233dc03f30c8da6ba54e3cc1ff01 Mon Sep 17 00:00:00 2001
From: Andreas Hager
Date: Sat, 30 Sep 2023 06:52:49 +0200
Subject: [PATCH 3/7] #278 fix test execution
---
jte/src/main/java/gg/jte/compiler/TemplateCompiler.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/jte/src/main/java/gg/jte/compiler/TemplateCompiler.java b/jte/src/main/java/gg/jte/compiler/TemplateCompiler.java
index a7a71fba..a8665ba9 100644
--- a/jte/src/main/java/gg/jte/compiler/TemplateCompiler.java
+++ b/jte/src/main/java/gg/jte/compiler/TemplateCompiler.java
@@ -245,7 +245,8 @@ private Module readModuleInformation(String alias, CodeResolver codeResolver) {
Map children = new LinkedHashMap<>();
for ( ModuleImport moduleImport : moduleInfo.imports() ) {
- DirectoryCodeResolver moduleDirectoryResolver = new DirectoryCodeResolver(directoryCodeResolver.getRoot().resolve(moduleImport.from()));
+ Path modulePath = directoryCodeResolver.getRoot().resolve(moduleImport.from()).normalize();
+ DirectoryCodeResolver moduleDirectoryResolver = new DirectoryCodeResolver(modulePath);
children.put(moduleImport.alias(), readModuleInformation(moduleImport.alias(), moduleDirectoryResolver));
}
From 7cb7ff1af970c1e759e92e5e7bee10a13ffe8db5 Mon Sep 17 00:00:00 2001
From: Andreas Hager
Date: Sat, 30 Sep 2023 08:35:00 +0200
Subject: [PATCH 4/7] #278 template names are properly normalized
---
.../java/gg/jte/compiler/TemplateCompiler.java | 2 ++
.../main/java/gg/jte/compiler/module/Module.java | 12 ++++++++++++
.../java/gg/jte/TemplateEngine_ModulesTest.java | 16 ++++++++++++++++
3 files changed, 30 insertions(+)
diff --git a/jte/src/main/java/gg/jte/compiler/TemplateCompiler.java b/jte/src/main/java/gg/jte/compiler/TemplateCompiler.java
index a8665ba9..a8f4e1cd 100644
--- a/jte/src/main/java/gg/jte/compiler/TemplateCompiler.java
+++ b/jte/src/main/java/gg/jte/compiler/TemplateCompiler.java
@@ -284,6 +284,8 @@ public ClassInfo generateTemplateCall(String name, LinkedHashSetline chart (checkout)
line chart (core)""");
}
+ @Test
+ void emptyTopLevelModule_generateAll() {
+ DirectoryCodeResolver codeResolver = new DirectoryCodeResolver(Path.of("src/test/modules/empty-top-level-module"));
+ TemplateEngine templateEngine = TemplateEngine.create(codeResolver, ContentType.Html);
+
+ List templates = templateEngine.generateAll();
+
+ assertThat(templates).containsExactlyInAnyOrder(
+ "gg/jte/generated/ondemand/apexcharts/JtelinechartGenerated.java",
+ "gg/jte/generated/ondemand/checkout/JtepageGenerated.java",
+ "gg/jte/generated/ondemand/core/JtelayoutGenerated.java",
+ "gg/jte/generated/ondemand/core/component/JtecssGenerated.java"
+ );
+ }
+
// TODO adjust precompileAll() and generateAll() to iterate over all module files as well!
}
From cc17d6083d6e9d88f1f57bc7b823bc4a52588b01 Mon Sep 17 00:00:00 2001
From: Andreas Hager
Date: Sun, 1 Oct 2023 07:21:26 +0200
Subject: [PATCH 5/7] #278 ensure unused templates are still generated
---
jte/src/test/java/gg/jte/TemplateEngine_ModulesTest.java | 1 +
jte/src/test/modules/empty-top-level-module/checkout/unused.jte | 1 +
2 files changed, 2 insertions(+)
create mode 100644 jte/src/test/modules/empty-top-level-module/checkout/unused.jte
diff --git a/jte/src/test/java/gg/jte/TemplateEngine_ModulesTest.java b/jte/src/test/java/gg/jte/TemplateEngine_ModulesTest.java
index 095053ec..753ecad3 100644
--- a/jte/src/test/java/gg/jte/TemplateEngine_ModulesTest.java
+++ b/jte/src/test/java/gg/jte/TemplateEngine_ModulesTest.java
@@ -81,6 +81,7 @@ void emptyTopLevelModule_generateAll() {
assertThat(templates).containsExactlyInAnyOrder(
"gg/jte/generated/ondemand/apexcharts/JtelinechartGenerated.java",
"gg/jte/generated/ondemand/checkout/JtepageGenerated.java",
+ "gg/jte/generated/ondemand/checkout/JteunusedGenerated.java",
"gg/jte/generated/ondemand/core/JtelayoutGenerated.java",
"gg/jte/generated/ondemand/core/component/JtecssGenerated.java"
);
diff --git a/jte/src/test/modules/empty-top-level-module/checkout/unused.jte b/jte/src/test/modules/empty-top-level-module/checkout/unused.jte
new file mode 100644
index 00000000..94a7ca5e
--- /dev/null
+++ b/jte/src/test/modules/empty-top-level-module/checkout/unused.jte
@@ -0,0 +1 @@
+I'm not used but should still be generated!
\ No newline at end of file
From fd09d6d28d8e5f7ea04db63b4235b18070958765 Mon Sep 17 00:00:00 2001
From: Andreas Hager
Date: Sun, 1 Oct 2023 07:45:46 +0200
Subject: [PATCH 6/7] #278 add support for parent module, similar to parent-pom
---
.../gg/jte/compiler/TemplateCompiler.java | 23 ++++++++------
.../java/gg/jte/compiler/module/Module.java | 30 +++++++++++++++---
.../compiler/module/ModuleCodeResolver.java | 7 +++++
.../gg/jte/compiler/module/ModuleInfo.java | 2 +-
.../jte/compiler/module/ModuleInfoParser.java | 11 +++++--
.../gg/jte/TemplateEngine_ModulesTest.java | 31 +++++++++++++++++--
.../modules/empty-top-level-module/.jteroot | 1 +
7 files changed, 85 insertions(+), 20 deletions(-)
diff --git a/jte/src/main/java/gg/jte/compiler/TemplateCompiler.java b/jte/src/main/java/gg/jte/compiler/TemplateCompiler.java
index a8f4e1cd..22b29ccb 100644
--- a/jte/src/main/java/gg/jte/compiler/TemplateCompiler.java
+++ b/jte/src/main/java/gg/jte/compiler/TemplateCompiler.java
@@ -58,7 +58,7 @@ public Template load(String name) {
@Override
public Template hotReload(String name) {
- LinkedHashSet classDefinitions = generate(Collections.singletonList(name), true);
+ LinkedHashSet classDefinitions = generate(Collections.singletonList(name), true, readModuleInformation("", codeResolver));
classDefinitions.removeIf(c -> !c.isChanged());
if (!classDefinitions.isEmpty()) {
@@ -85,18 +85,24 @@ public void cleanAll() {
@Override
public List generateAll() {
- LinkedHashSet classDefinitions = generate(codeResolver.resolveAllTemplateNames(), false);
+ Module module = readModuleInformation("", codeResolver);
+ Collection names = module.resolveAllTemplateNames();
+ LinkedHashSet classDefinitions = generate(names, false, module);
+
return classDefinitions.stream().map(ClassDefinition::getSourceFileName).collect(Collectors.toList());
}
@Override
public List precompileAll() {
- LinkedHashSet classDefinitions = generate(codeResolver.resolveAllTemplateNames(), false);
+ Module module = readModuleInformation("", codeResolver);
+ Collection names = module.resolveAllTemplateNames();
+ LinkedHashSet classDefinitions = generate(names, false, module);
+
return precompileClasses(classDefinitions);
}
public List precompile(List names) {
- LinkedHashSet classDefinitions = generate(names, false);
+ LinkedHashSet classDefinitions = generate(names, false, readModuleInformation("", codeResolver));
return precompileClasses(classDefinitions);
}
@@ -167,8 +173,7 @@ ClassCompiler createCompiler(String extension) {
}
}
- private LinkedHashSet generate(List names, boolean trackChanges ) {
- Module module = readModuleInformation("", codeResolver);
+ private LinkedHashSet generate(Collection names, boolean trackChanges, Module module) {
LinkedHashSet classDefinitions = new LinkedHashSet<>();
for (String name : names) {
@@ -234,11 +239,11 @@ private LinkedHashSet generate(List names, boolean trac
private Module readModuleInformation(String alias, CodeResolver codeResolver) {
String jteRootContent = codeResolver.resolve(".jteroot");
if (jteRootContent == null) {
- return new Module(alias, codeResolver, Map.of());
+ return new Module(alias, codeResolver, Map.of(), false);
}
if (!(codeResolver instanceof DirectoryCodeResolver directoryCodeResolver)) {
- return new Module(alias, codeResolver, Map.of());
+ return new Module(alias, codeResolver, Map.of(), false);
}
ModuleInfo moduleInfo = ModuleInfoParser.parse(jteRootContent);
@@ -250,7 +255,7 @@ private Module readModuleInformation(String alias, CodeResolver codeResolver) {
children.put(moduleImport.alias(), readModuleInformation(moduleImport.alias(), moduleDirectoryResolver));
}
- return new Module(alias, codeResolver, children);
+ return new Module(alias, codeResolver, children, moduleInfo.parent());
}
private LinkedHashSet initTemplateDependencies(String name) {
diff --git a/jte/src/main/java/gg/jte/compiler/module/Module.java b/jte/src/main/java/gg/jte/compiler/module/Module.java
index 0ca20feb..fab89f68 100644
--- a/jte/src/main/java/gg/jte/compiler/module/Module.java
+++ b/jte/src/main/java/gg/jte/compiler/module/Module.java
@@ -1,5 +1,8 @@
package gg.jte.compiler.module;
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.List;
import java.util.Map;
import gg.jte.CodeResolver;
@@ -19,11 +22,13 @@ public static String getModuleAlias(String name) {
private final String alias;
private final CodeResolver codeResolver;
private final Map children;
+ private final boolean parent;
- public Module( String alias, CodeResolver codeResolver, Map children ) {
+ public Module( String alias, CodeResolver codeResolver, Map children, boolean parent ) {
this.alias = alias;
this.codeResolver = isRoot() ? codeResolver : new ModuleCodeResolver(alias, codeResolver);
this.children = children;
+ this.parent = parent;
}
public Module resolve(String name) {
@@ -60,11 +65,26 @@ public boolean isRoot() {
return alias.isEmpty();
}
- public String getAlias() {
- return alias;
- }
-
public CodeResolver getCodeResolver() {
return codeResolver;
}
+
+ public Collection resolveAllTemplateNames() {
+ LinkedHashSet result = new LinkedHashSet<>();
+ resolveAllTemplateNames(result);
+ return result;
+ }
+
+ private void resolveAllTemplateNames(LinkedHashSet result) {
+ if (!parent) {
+ List names = codeResolver.resolveAllTemplateNames();
+ for (String name : names) {
+ result.add(normalize(name));
+ }
+ }
+
+ for (Module module : children.values()) {
+ module.resolveAllTemplateNames(result);
+ }
+ }
}
diff --git a/jte/src/main/java/gg/jte/compiler/module/ModuleCodeResolver.java b/jte/src/main/java/gg/jte/compiler/module/ModuleCodeResolver.java
index a8e88f5e..0f267b7e 100644
--- a/jte/src/main/java/gg/jte/compiler/module/ModuleCodeResolver.java
+++ b/jte/src/main/java/gg/jte/compiler/module/ModuleCodeResolver.java
@@ -3,6 +3,8 @@
import gg.jte.CodeResolver;
import gg.jte.TemplateNotFoundException;
+import java.util.List;
+
public class ModuleCodeResolver implements CodeResolver {
@@ -29,6 +31,11 @@ public long getLastModified( String name ) {
return codeResolver.getLastModified(removeAlias(name));
}
+ @Override
+ public List resolveAllTemplateNames() {
+ return codeResolver.resolveAllTemplateNames();
+ }
+
@Override
public boolean exists( String name ) {
return codeResolver.exists(removeAlias(name));
diff --git a/jte/src/main/java/gg/jte/compiler/module/ModuleInfo.java b/jte/src/main/java/gg/jte/compiler/module/ModuleInfo.java
index 4d82fe1e..204667fc 100644
--- a/jte/src/main/java/gg/jte/compiler/module/ModuleInfo.java
+++ b/jte/src/main/java/gg/jte/compiler/module/ModuleInfo.java
@@ -3,4 +3,4 @@
import java.util.List;
-public record ModuleInfo(List imports) {}
+public record ModuleInfo(boolean parent, List imports) {}
diff --git a/jte/src/main/java/gg/jte/compiler/module/ModuleInfoParser.java b/jte/src/main/java/gg/jte/compiler/module/ModuleInfoParser.java
index 1efd5e27..c73cb880 100644
--- a/jte/src/main/java/gg/jte/compiler/module/ModuleInfoParser.java
+++ b/jte/src/main/java/gg/jte/compiler/module/ModuleInfoParser.java
@@ -3,6 +3,7 @@
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
+import java.util.List;
public class ModuleInfoParser {
@@ -29,7 +30,8 @@ private ModuleInfoParser( String moduleInfo ) {
}
private ModuleInfo parse() {
- ModuleInfo result = new ModuleInfo(new ArrayList<>());
+ boolean parent = false;
+ List imports = new ArrayList<>();
push(Mode.Root);
@@ -44,13 +46,16 @@ private ModuleInfo parse() {
importMode.alias = extractFromLastIndex(-4).trim();
} else if ( currentChar == '\n' || i == endIndex - 1) {
importMode.from = extractFromLastIndex(1).trim();
- result.imports().add(new ModuleImport(importMode.alias, importMode.from));
+ imports.add(new ModuleImport(importMode.alias, importMode.from));
pop();
}
+ } else if (currentMode == Mode.Root && regionMatches("@parent")) {
+ parent = true;
+ lastIndex = i + 1;
}
}
- return result;
+ return new ModuleInfo(parent, imports);
}
private String extractFromLastIndex(int offset) {
diff --git a/jte/src/test/java/gg/jte/TemplateEngine_ModulesTest.java b/jte/src/test/java/gg/jte/TemplateEngine_ModulesTest.java
index 753ecad3..135f5268 100644
--- a/jte/src/test/java/gg/jte/TemplateEngine_ModulesTest.java
+++ b/jte/src/test/java/gg/jte/TemplateEngine_ModulesTest.java
@@ -72,7 +72,7 @@ line chart (checkout)
}
@Test
- void emptyTopLevelModule_generateAll() {
+ void generateAll_emptyTopLevelModule() {
DirectoryCodeResolver codeResolver = new DirectoryCodeResolver(Path.of("src/test/modules/empty-top-level-module"));
TemplateEngine templateEngine = TemplateEngine.create(codeResolver, ContentType.Html);
@@ -87,5 +87,32 @@ void emptyTopLevelModule_generateAll() {
);
}
- // TODO adjust precompileAll() and generateAll() to iterate over all module files as well!
+ @Test
+ void generateAll_threeModulesSameAlias() {
+ DirectoryCodeResolver codeResolver = new DirectoryCodeResolver(Path.of("src/test/modules/three-modules-same-alias/app"));
+ TemplateEngine templateEngine = TemplateEngine.create(codeResolver, ContentType.Html);
+
+ List templates = templateEngine.generateAll();
+
+ assertThat(templates).containsExactlyInAnyOrder(
+ "gg/jte/generated/ondemand/JtepageGenerated.java",
+ "gg/jte/generated/ondemand/core/JtelayoutGenerated.java",
+ "gg/jte/generated/ondemand/apexcharts/JtelinechartGenerated.java"
+ );
+ }
+
+ @Test
+ void generateAll_threeModulesDifferentAlias() {
+ DirectoryCodeResolver codeResolver = new DirectoryCodeResolver(Path.of("src/test/modules/three-modules-different-alias/app"));
+ TemplateEngine templateEngine = TemplateEngine.create(codeResolver, ContentType.Html);
+
+ List templates = templateEngine.generateAll();
+
+ assertThat(templates).containsExactlyInAnyOrder(
+ "gg/jte/generated/ondemand/JtepageGenerated.java",
+ "gg/jte/generated/ondemand/core/JtelayoutGenerated.java",
+ "gg/jte/generated/ondemand/apexcharts/JtelinechartGenerated.java",
+ "gg/jte/generated/ondemand/charts/JtelinechartGenerated.java"
+ );
+ }
}
diff --git a/jte/src/test/modules/empty-top-level-module/.jteroot b/jte/src/test/modules/empty-top-level-module/.jteroot
index d65d1049..13384d4b 100644
--- a/jte/src/test/modules/empty-top-level-module/.jteroot
+++ b/jte/src/test/modules/empty-top-level-module/.jteroot
@@ -1,3 +1,4 @@
+@parent
@import apexcharts from apexcharts
@import checkout from checkout
@import core from core
\ No newline at end of file
From 96f2c359ede41e0691f686178c12ed23cea23321 Mon Sep 17 00:00:00 2001
From: Andreas Hager
Date: Sun, 1 Oct 2023 07:58:50 +0200
Subject: [PATCH 7/7] #278 small refactoring
---
.../gg/jte/compiler/TemplateCompiler.java | 38 ++++---------------
.../java/gg/jte/compiler/module/Module.java | 29 ++++++++++++--
2 files changed, 33 insertions(+), 34 deletions(-)
diff --git a/jte/src/main/java/gg/jte/compiler/TemplateCompiler.java b/jte/src/main/java/gg/jte/compiler/TemplateCompiler.java
index 22b29ccb..4e797645 100644
--- a/jte/src/main/java/gg/jte/compiler/TemplateCompiler.java
+++ b/jte/src/main/java/gg/jte/compiler/TemplateCompiler.java
@@ -9,14 +9,10 @@
import gg.jte.compiler.java.JavaClassCompiler;
import gg.jte.compiler.java.JavaCodeGenerator;
import gg.jte.compiler.module.Module;
-import gg.jte.compiler.module.ModuleImport;
-import gg.jte.compiler.module.ModuleInfo;
-import gg.jte.compiler.module.ModuleInfoParser;
import gg.jte.extension.api.JteConfig;
import gg.jte.extension.api.JteExtension;
import gg.jte.extension.api.TemplateDescription;
import gg.jte.output.FileOutput;
-import gg.jte.resolve.DirectoryCodeResolver;
import gg.jte.runtime.*;
import java.io.IOException;
@@ -58,7 +54,7 @@ public Template load(String name) {
@Override
public Template hotReload(String name) {
- LinkedHashSet classDefinitions = generate(Collections.singletonList(name), true, readModuleInformation("", codeResolver));
+ LinkedHashSet classDefinitions = generate(Collections.singletonList(name), true, getModule());
classDefinitions.removeIf(c -> !c.isChanged());
if (!classDefinitions.isEmpty()) {
@@ -85,7 +81,7 @@ public void cleanAll() {
@Override
public List generateAll() {
- Module module = readModuleInformation("", codeResolver);
+ Module module = getModule();
Collection names = module.resolveAllTemplateNames();
LinkedHashSet classDefinitions = generate(names, false, module);
@@ -94,7 +90,7 @@ public List generateAll() {
@Override
public List precompileAll() {
- Module module = readModuleInformation("", codeResolver);
+ Module module = getModule();
Collection names = module.resolveAllTemplateNames();
LinkedHashSet classDefinitions = generate(names, false, module);
@@ -102,7 +98,7 @@ public List precompileAll() {
}
public List precompile(List names) {
- LinkedHashSet classDefinitions = generate(names, false, readModuleInformation("", codeResolver));
+ LinkedHashSet classDefinitions = generate(names, false, getModule());
return precompileClasses(classDefinitions);
}
@@ -236,28 +232,6 @@ private LinkedHashSet generate(Collection names, boolea
return classDefinitions;
}
- private Module readModuleInformation(String alias, CodeResolver codeResolver) {
- String jteRootContent = codeResolver.resolve(".jteroot");
- if (jteRootContent == null) {
- return new Module(alias, codeResolver, Map.of(), false);
- }
-
- if (!(codeResolver instanceof DirectoryCodeResolver directoryCodeResolver)) {
- return new Module(alias, codeResolver, Map.of(), false);
- }
-
- ModuleInfo moduleInfo = ModuleInfoParser.parse(jteRootContent);
- Map children = new LinkedHashMap<>();
-
- for ( ModuleImport moduleImport : moduleInfo.imports() ) {
- Path modulePath = directoryCodeResolver.getRoot().resolve(moduleImport.from()).normalize();
- DirectoryCodeResolver moduleDirectoryResolver = new DirectoryCodeResolver(modulePath);
- children.put(moduleImport.alias(), readModuleInformation(moduleImport.alias(), moduleDirectoryResolver));
- }
-
- return new Module(alias, codeResolver, children, moduleInfo.parent());
- }
-
private LinkedHashSet initTemplateDependencies(String name) {
LinkedHashSet templateDependencies = new LinkedHashSet<>();
templateDependencies.add(new TemplateDependency(name, codeResolver.getLastModified(name)));
@@ -385,4 +359,8 @@ private JteExtension loadExtension(Map.Entry> extens
}
}
+ private Module getModule() {
+ return Module.create("", codeResolver);
+ }
+
}
diff --git a/jte/src/main/java/gg/jte/compiler/module/Module.java b/jte/src/main/java/gg/jte/compiler/module/Module.java
index fab89f68..1022d7f6 100644
--- a/jte/src/main/java/gg/jte/compiler/module/Module.java
+++ b/jte/src/main/java/gg/jte/compiler/module/Module.java
@@ -1,15 +1,36 @@
package gg.jte.compiler.module;
-import java.util.Collection;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
+import java.nio.file.Path;
+import java.util.*;
import gg.jte.CodeResolver;
+import gg.jte.resolve.DirectoryCodeResolver;
public final class Module {
+ public static Module create(String alias, CodeResolver codeResolver) {
+ String jteRootContent = codeResolver.resolve(".jteroot");
+ if (jteRootContent == null) {
+ return new Module(alias, codeResolver, Map.of(), false);
+ }
+
+ if (!(codeResolver instanceof DirectoryCodeResolver directoryCodeResolver)) {
+ return new Module(alias, codeResolver, Map.of(), false);
+ }
+
+ ModuleInfo moduleInfo = ModuleInfoParser.parse(jteRootContent);
+ Map children = new LinkedHashMap<>();
+
+ for ( ModuleImport moduleImport : moduleInfo.imports() ) {
+ Path modulePath = directoryCodeResolver.getRoot().resolve(moduleImport.from()).normalize();
+ DirectoryCodeResolver moduleDirectoryResolver = new DirectoryCodeResolver(modulePath);
+ children.put(moduleImport.alias(), create(moduleImport.alias(), moduleDirectoryResolver));
+ }
+
+ return new Module(alias, codeResolver, children, moduleInfo.parent());
+ }
+
public static String getModuleAlias(String name) {
int index = name.indexOf('/');
if (index == -1) {