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("\n

App 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) {