diff --git a/README.md b/README.md index d4306c2..7dc6cc1 100644 --- a/README.md +++ b/README.md @@ -203,11 +203,12 @@ One restriction is that a state and a messages may share have the same name, i.e If the parser is successful it will hold the following data in the AST ```java -public record DocumentNode( - Map config, - Set typeDefinitions, - List endpoints, - Set states) { +public record GeneratorNode( + Map config, + Set typeDefinitions, + List endpoints, + Set states, + Meta meta) { } ``` @@ -304,3 +305,14 @@ public record TransitionNode(String message, String toState) { ``` * `name` is the message name. * `toState` is the name of the target state. + +### Meta + +The meta container holds information about the template file used to generate the output file. +It holds the subdirectory below the given `templateDir` where the template was found. + +This is useful to generate e.g. java `package`statements like this: + +```injectedfreemarker +<#list meta.templateDirectories>package <#items as dir>${dir}<#sep>.; +``` \ No newline at end of file diff --git a/endpoints-templates/endpoints.txt.ftl b/endpoints-templates/endpoints.txt.ftl index 9a779fb..4904c00 100644 --- a/endpoints-templates/endpoints.txt.ftl +++ b/endpoints-templates/endpoints.txt.ftl @@ -1,3 +1,5 @@ +Generated from template: ${meta.templateFile} + <#list endpoints as endpoint> <#list endpoint.paths.paths> <#items as segment>/${segment} diff --git a/endpoints-templates/nu/zoom/dsl/Codecs.scala.ftl b/endpoints-templates/nu/zoom/dsl/Codecs.scala.ftl index f11070f..7ea382d 100644 --- a/endpoints-templates/nu/zoom/dsl/Codecs.scala.ftl +++ b/endpoints-templates/nu/zoom/dsl/Codecs.scala.ftl @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package ${config.package} +<#list meta.templateDirectories>package <#items as dir>${dir}<#sep>.; object Codecs: <#list typeDefinitions as type> diff --git a/endpoints-templates/nu/zoom/dsl/Endpoints.scala.ftl b/endpoints-templates/nu/zoom/dsl/Endpoints.scala.ftl index a68864c..fbc3538 100644 --- a/endpoints-templates/nu/zoom/dsl/Endpoints.scala.ftl +++ b/endpoints-templates/nu/zoom/dsl/Endpoints.scala.ftl @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package ${config.package} +<#list meta.templateDirectories>package<#items as dir>${dir}<#sep>.; class Endpoints: <#list endpoints as endpoint> diff --git a/endpoints-templates/nu/zoom/dsl/Protocol.scala.ftl b/endpoints-templates/nu/zoom/dsl/Protocol.scala.ftl index faa5d55..41e6547 100644 --- a/endpoints-templates/nu/zoom/dsl/Protocol.scala.ftl +++ b/endpoints-templates/nu/zoom/dsl/Protocol.scala.ftl @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package ${config.package} +<#list meta.templateDirectories>package<#items as dir>${dir}<#sep>.; object Protocol: <#list typeDefinitions?sort as type> diff --git a/parser/src/main/java/nu/zoom/dsl/ast/DocumentNode.java b/parser/src/main/java/nu/zoom/dsl/ast/DocumentNode.java index fcb8621..7edb239 100644 --- a/parser/src/main/java/nu/zoom/dsl/ast/DocumentNode.java +++ b/parser/src/main/java/nu/zoom/dsl/ast/DocumentNode.java @@ -13,6 +13,7 @@ // limitations under the License. package nu.zoom.dsl.ast; +import java.nio.file.Path; import java.util.List; import java.util.Map; import java.util.Set; diff --git a/parser/src/main/java/nu/zoom/dsl/ast/GeneratorNode.java b/parser/src/main/java/nu/zoom/dsl/ast/GeneratorNode.java new file mode 100644 index 0000000..2cea7ca --- /dev/null +++ b/parser/src/main/java/nu/zoom/dsl/ast/GeneratorNode.java @@ -0,0 +1,13 @@ +package nu.zoom.dsl.ast; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +public record GeneratorNode( + Map config, + Set typeDefinitions, + List endpoints, + Set states, + Meta meta) { +} diff --git a/parser/src/main/java/nu/zoom/dsl/ast/Meta.java b/parser/src/main/java/nu/zoom/dsl/ast/Meta.java new file mode 100644 index 0000000..567f3ab --- /dev/null +++ b/parser/src/main/java/nu/zoom/dsl/ast/Meta.java @@ -0,0 +1,9 @@ +package nu.zoom.dsl.ast; + +import java.util.List; + +public record Meta( + List templateDirectories, + String templateFile +) { +} diff --git a/parser/src/main/java/nu/zoom/dsl/freemarker/Generator.java b/parser/src/main/java/nu/zoom/dsl/freemarker/Generator.java index 1ac2cb0..0458669 100644 --- a/parser/src/main/java/nu/zoom/dsl/freemarker/Generator.java +++ b/parser/src/main/java/nu/zoom/dsl/freemarker/Generator.java @@ -18,63 +18,82 @@ import freemarker.template.Template; import freemarker.template.TemplateException; import freemarker.template.TemplateExceptionHandler; import nu.zoom.dsl.ast.DocumentNode; +import nu.zoom.dsl.ast.GeneratorNode; +import nu.zoom.dsl.ast.Meta; import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.nio.file.FileVisitOption; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.stream.Collectors; import java.util.stream.Stream; public class Generator { - private final Path templatesDir; - private final DocumentNode data; - private final Path outputDir; - private final Configuration cfg; - private final String TEMPLATE_EXTENSION = ".ftl"; - private final int TEMPLATE_EXTENSION_LENGTH = TEMPLATE_EXTENSION.length(); + private final Path templatesDir; + private final DocumentNode documentNode; + private final Path outputDir; + private final Configuration cfg; + private final String TEMPLATE_EXTENSION = ".ftl"; + private final int TEMPLATE_EXTENSION_LENGTH = TEMPLATE_EXTENSION.length(); - public Generator(Path templatesDir, DocumentNode data, Path outputDir) throws IOException { - this.templatesDir = Objects.requireNonNull(templatesDir); - this.data = Objects.requireNonNull(data); - this.outputDir = Objects.requireNonNull(outputDir); - this.cfg = new Configuration(Configuration.VERSION_2_3_34); - cfg.setDirectoryForTemplateLoading(templatesDir.toFile()); - cfg.setDefaultEncoding("UTF-8"); - cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); - cfg.setLogTemplateExceptions(false); - cfg.setWrapUncheckedExceptions(true); - cfg.setFallbackOnNullLoopVariable(false); - } + public Generator(Path templatesDir, DocumentNode documentNode, Path outputDir) throws IOException { + this.templatesDir = Objects.requireNonNull(templatesDir); + this.documentNode = Objects.requireNonNull(documentNode); + this.outputDir = Objects.requireNonNull(outputDir); + this.cfg = new Configuration(Configuration.VERSION_2_3_34); + cfg.setDirectoryForTemplateLoading(templatesDir.toFile()); + cfg.setDefaultEncoding("UTF-8"); + cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); + cfg.setLogTemplateExceptions(false); + cfg.setWrapUncheckedExceptions(true); + cfg.setFallbackOnNullLoopVariable(false); + } - public List generate() throws IOException, TemplateException { - try (Stream files = Files.walk(templatesDir)) { - List templates = files - .filter(p -> { - var fname = p.getFileName().toString(); - return fname.length() > TEMPLATE_EXTENSION_LENGTH && fname.endsWith(TEMPLATE_EXTENSION) ; - } - ) - .map(p -> templatesDir.relativize(p)) - .toList(); - ArrayList out = new ArrayList<>(); - for (Path template : templates) { - Path outpath = outputDir.resolve(outputFilenameFromTemplate(template.toString())); - Files.createDirectories(outpath.getParent()); - Template ftl = this.cfg.getTemplate(template.toString()); - try (var outw = Files.newBufferedWriter(outpath, StandardCharsets.UTF_8)) { - ftl.process(this.data, outw); - out.add(outpath); - } - } - return out; - } - } + public List generate() throws IOException, TemplateException { + try (Stream files = Files.walk(templatesDir)) { + List templates = files + .filter(p -> { + var fname = p.getFileName().toString(); + return fname.length() > TEMPLATE_EXTENSION_LENGTH && fname.endsWith(TEMPLATE_EXTENSION); + } + ) + .map(p -> templatesDir.relativize(p)) + .toList(); + ArrayList out = new ArrayList<>(); + for (Path template : templates) { + Path outpath = outputDir.resolve(outputFilenameFromTemplate(template.toString())); + Files.createDirectories(outpath.getParent()); + Path templateSubdirectory = template.getParent(); + ArrayList templateDirectories= new ArrayList<>() ; + if (templateSubdirectory != null) { + var ti = templateSubdirectory.iterator(); + while (ti.hasNext()) { + templateDirectories.add(ti.next().toString()); + } + } + String templateName = template.getFileName().toString(); + Meta meta = new Meta(templateDirectories, templateName); + GeneratorNode generatorNode = new GeneratorNode( + this.documentNode.config(), + this.documentNode.typeDefinitions(), + this.documentNode.endpoints(), + this.documentNode.states(), + meta + ); + Template ftl = this.cfg.getTemplate(template.toString()); + try (var outw = Files.newBufferedWriter(outpath, StandardCharsets.UTF_8)) { + ftl.process(generatorNode, outw); + out.add(outpath); + } + } + return out; + } + } - private String outputFilenameFromTemplate(String template) { - return template.substring(0, template.length() - TEMPLATE_EXTENSION_LENGTH); - } + private String outputFilenameFromTemplate(String template) { + return template.substring(0, template.length() - TEMPLATE_EXTENSION_LENGTH); + } }