From e87599708ea7f14d4092abe02aab8ba8b36fada8 Mon Sep 17 00:00:00 2001 From: Johan Maasing Date: Sun, 20 Apr 2025 11:48:27 +0200 Subject: [PATCH 01/10] [maven-release-plugin] prepare for next development iteration --- endgen-dist/pom.xml | 2 +- parser/pom.xml | 2 +- pom.xml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/endgen-dist/pom.xml b/endgen-dist/pom.xml index 729e41a..dda6922 100644 --- a/endgen-dist/pom.xml +++ b/endgen-dist/pom.xml @@ -5,7 +5,7 @@ nu.zoom.dsl endgen - 1.1 + 1.2-SNAPSHOT endgen-dist diff --git a/parser/pom.xml b/parser/pom.xml index 7444c5f..ba9d182 100644 --- a/parser/pom.xml +++ b/parser/pom.xml @@ -20,7 +20,7 @@ nu.zoom.dsl endgen - 1.1 + 1.2-SNAPSHOT parser diff --git a/pom.xml b/pom.xml index f53798f..86744cc 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ nu.zoom.dsl endgen - 1.1 + 1.2-SNAPSHOT pom @@ -59,7 +59,7 @@ scm:git:https://codeberg.org/darkstar/endgen.git scm:git:ssh://git@vcs.zoom.nu:1122/zoom/endgen.git - v1.1 + admin-parent-1.1 From bc458299dc85e1a0d45f2194ec1e16ab1ec98372 Mon Sep 17 00:00:00 2001 From: Johan Maasing Date: Sun, 20 Apr 2025 12:15:42 +0200 Subject: [PATCH 02/10] Fixup documentation --- README.md | 85 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 2e73f92..d23fa85 100644 --- a/README.md +++ b/README.md @@ -37,10 +37,10 @@ Endgen currently contains two separate parsers: * endpoint - A DSL for expressing HTTP endpoints. * state - A DSL for expressing state and transitions. -Which parser that is used to read the input file is determined by the file name ending -'.endpoints' or '.states' or by a command line argument. +Only one parser will be sued when reading a file. Determined by the file name ending; +'.endpoints', or '.states', or by a command line argument. -The endpoint DSL and the state DSL share the grammar for expressing configuration and data types +The endpoint-DSL and the state-DSL share the grammar for expressing configuration and data types ,see below for details. ## How to Run @@ -89,15 +89,20 @@ a very limited DSL, you can for example not express what type of HTTP Verb to us no plans to extend the DSL to do that either. ## DSL -This is the ANTLR grammar for the root of the DSL +This is the ANTLR grammar for the root of the Endpoint-DSL ```antlrv4 document : generatorconfig? (namedTypeDeclaration|endpoint)* ; ``` +the corresponding grammar for the root of the State-DSL + +```antlrv4 +document : generatorconfig? transition (',' transition)* ; +``` + ### Configuration block -Meaning that the DSL file has an optional `generatorconfig` block at the top. Then you can write either; a type -definition, or an endpoint declaration, as many times as you like. +Both types of DSL files has an optional `generatorconfig` block at the top. Here is an example: ``` @@ -105,25 +110,32 @@ Here is an example: package: se.rutdev.senash, mykey: myvalue } +``` +This consists of a config block with 2 items, the 'package' and the 'mykey' definition. These are available to be used +in the freemarker template as a Map of String-keys to String-values. + +### Endpoint DSL +After the optional configuration block you can write either; a type definition, or an endpoint declaration, and repeat +as many times as you like. + +Here is an example: +``` /some/endpoint <- SomeType(foo:String) Embedded(foo:Bar) /some/other/endpoint <- (bar:Seq[Embedded]) ``` -This consists of a config block with 2 items, the 'package' and the 'mykey' definition. These are available to be used -in the freemarker template as a Map of String-keys to String-values. - ### Endpoint definition `/some/endpoint <- SomeType(foo:String)` is an endpoint definition. It declares one endpoint that have a request body data type called `SomeType` that has a field called `foo` of the type `String`. ### Data types -The DSL uses Scala convention of writing data types after the field name separated by a colon. Of course the DSL parser -does not know anything about java or scala types, as far as it is concerned these are 2 strings and the first one is -just named field-name and the other string is named field-type. +Both DSL-grammars use the Scala convention of writing data types after the field name separated by a colon. Of course +the parsers do not know anything about java or scala types, as far as the parser is concerned these are 2 strings and +the first one is just named: field-name and the other string is named: field-type. `Embedded(foo:Bar)` is a `namedTypeDeclaration` which is parsed the same way as the request type above. But isn't tied to a specific endpoint. @@ -148,45 +160,44 @@ It is possible to have an optional response data type declared like so: The right pointing arrow `->` denotes a response type, it can be an anonymous data type in which case the parser till name it from the last path segment and add 'Response' to the end of the data type name. -### State grammar - +### State DSL This is an example of a state file: ``` -start -> middle: message, -middle -> middle: selfmessage, -middle -> end: endmessage +start -> middle: message, +middle -> middle: selfmessage, +middle -> end: endmessage ``` +The file declares 3 transitions. The first line states: Transition from the 'start' state to the 'middle' state with +the message 'message'. -It contains 3 state definitions `start`, `middle` and `end`. A state definition will be parsed as a data type with -the name of the state as the type name. - -It also contains 3 message definitions `message`, `selfmessage` and `endmessage`. Message definitions will also be -parsed as data types. +From this we can see that the file contains 3 state definitions `start`, `middle` and `end`. +A state definition will be parsed as a data type with the name of the state as the type name. It also contains 3 +message definitions `message`, `selfmessage` and `endmessage`. Message definitions will also be parsed as data types. Since the parser will extract datatypes it is possible to define the fields of the data types. This is a slightly more complicated example: ``` -start(foo:Foo) -> middle: message(a: String), -middle(bar:Bar) -> middle: selfmessage, -middle -> end: endmessage +start -> middle: message(a: String), +middle(bar:Bar) -> middle: selfmessage, +middle -> end: endmessage ``` -Where for example the data type for `middle` will have the field declaration with the name `bar` and the type `Bar`. +The data type for `middle` will have a field declaration with the name `bar` and the type `Bar`. Fields for the same state data type, or message data type, will be merged. Here is a complex example: ``` -start(s:S) -> middle(foo:foo): message(foo:foo), -middle -> middle(bar:bar): selfmessage(bar:bar), -middle -> end: message(bar:baz) +start(s:S) -> middle(foo:foo): message(foo:foo), +middle -> middle(bar:bar): selfmessage(bar:bar), +middle -> end: message(bar:baz) ``` -Not that we can declare fields on both the `from` and `to` state declarations. The `middle` datat type will have field +Note that we can declare fields on both the `from` and `to` state declarations. The `middle` datat type will have field definitons for `foo` and `bar`. The data type for `message` will have fields for `foo` and `bar`. -One restriction is that states and messages may not have the same name, i.e. be parsed as the same data type. +One restriction is that a state and a messages may share have the same name, i.e. be parsed as the same data type. ## Generating If the parser is successful it will hold the following data in the AST @@ -221,8 +232,8 @@ that writes the value for a config key called 'package'. `package ${config.package}` ### Data types -These are all the data types the parser have collected, either from explicit declarations, request payloads and response -bodies. +These are all the data types the parser have collected, either from explicit declarations, request payloads, response +bodies, states or messages. ```java public record TypeNode(String name, List fields) { } @@ -281,11 +292,15 @@ The set of states will hold items of this shape: public record StateNode(String name, String data, Set transitions) { } ``` +* `name` is the name of the state. +* `data` is the name of the data type for the state. +* `transistions` are the outgoing arrows from the named state. -and the transitions has this structure: +Transitions have this structure: ```injectedfreemarker public record TransitionNode(String message, String toState) { } ``` - +* `name` is the message name. +* `toState` is the name of the target state. From c1c062b6cf39fb41772b6869f4a2eb8349a9e5f6 Mon Sep 17 00:00:00 2001 From: Johan Maasing Date: Tue, 22 Apr 2025 20:28:17 +0200 Subject: [PATCH 03/10] Changed grammar for states --- README.md | 18 +++++++++--------- .../main/antlr4/nu/zoom/dsl/parser/States.g4 | 2 +- test01.states | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index d23fa85..d4306c2 100644 --- a/README.md +++ b/README.md @@ -163,9 +163,9 @@ name it from the last path segment and add 'Response' to the end of the data typ ### State DSL This is an example of a state file: ``` -start -> middle: message, -middle -> middle: selfmessage, -middle -> end: endmessage +start -> message -> middle , +middle -> selfmessage -> middle, +middle -> endmessage -> end ``` The file declares 3 transitions. The first line states: Transition from the 'start' state to the 'middle' state with the message 'message'. @@ -178,18 +178,18 @@ Since the parser will extract datatypes it is possible to define the fields of t complicated example: ``` -start -> middle: message(a: String), -middle(bar:Bar) -> middle: selfmessage, -middle -> end: endmessage +start -> message -> middle, +middle -> selfmessage -> middle(bar:bar), +middle -> message -> end ``` The data type for `middle` will have a field declaration with the name `bar` and the type `Bar`. Fields for the same state data type, or message data type, will be merged. Here is a complex example: ``` -start(s:S) -> middle(foo:foo): message(foo:foo), -middle -> middle(bar:bar): selfmessage(bar:bar), -middle -> end: message(bar:baz) +start(s:S) -> message(foo:foo) -> middle(foo:foo) , +middle -> selfmessage(bar:bar) -> middle(bar:bar), +middle -> message(bar:baz) -> end ``` Note that we can declare fields on both the `from` and `to` state declarations. The `middle` datat type will have field diff --git a/parser/src/main/antlr4/nu/zoom/dsl/parser/States.g4 b/parser/src/main/antlr4/nu/zoom/dsl/parser/States.g4 index dbfe628..d2a2b4d 100644 --- a/parser/src/main/antlr4/nu/zoom/dsl/parser/States.g4 +++ b/parser/src/main/antlr4/nu/zoom/dsl/parser/States.g4 @@ -15,7 +15,7 @@ grammar States; import Common; document : generatorconfig? transition (',' transition)* ; -transition : from RIGHT_ARROW to COLON message ; +transition : from RIGHT_ARROW message RIGHT_ARROW to ; from : state ; to : state ; message : typeName typeDeclaration? ; diff --git a/test01.states b/test01.states index bcb304f..3b9a67a 100644 --- a/test01.states +++ b/test01.states @@ -16,6 +16,6 @@ { title: SomeNodes, package: nu.zoom.dsl.states } -start(s:S) -> middle(foo:foo): message(foo:foo), -middle -> middle(bar:bar): selfmessage(bar:bar), -middle -> end: message(bar:baz) +start(s:S) -> message(foo:foo) -> middle(foo:foo) , +middle -> selfmessage(bar:bar) -> middle(bar:bar), +middle -> message(bar:baz) -> end From 68dc70c17618b0feaaaebf3d9c258d25c9b29793 Mon Sep 17 00:00:00 2001 From: Johan Maasing Date: Fri, 2 May 2025 08:44:44 +0200 Subject: [PATCH 04/10] Makes it possible to put templates in subdirectories --- .../{ => nu/zoom/dsl}/Codecs.scala.ftl | 0 .../{ => nu/zoom/dsl}/Endpoints.scala.ftl | 0 .../{ => nu/zoom/dsl}/Protocol.scala.ftl | 0 .../nu/zoom/dsl/freemarker/Generator.java | 24 +++++++++++-------- 4 files changed, 14 insertions(+), 10 deletions(-) rename endpoints-templates/{ => nu/zoom/dsl}/Codecs.scala.ftl (100%) rename endpoints-templates/{ => nu/zoom/dsl}/Endpoints.scala.ftl (100%) rename endpoints-templates/{ => nu/zoom/dsl}/Protocol.scala.ftl (100%) diff --git a/endpoints-templates/Codecs.scala.ftl b/endpoints-templates/nu/zoom/dsl/Codecs.scala.ftl similarity index 100% rename from endpoints-templates/Codecs.scala.ftl rename to endpoints-templates/nu/zoom/dsl/Codecs.scala.ftl diff --git a/endpoints-templates/Endpoints.scala.ftl b/endpoints-templates/nu/zoom/dsl/Endpoints.scala.ftl similarity index 100% rename from endpoints-templates/Endpoints.scala.ftl rename to endpoints-templates/nu/zoom/dsl/Endpoints.scala.ftl diff --git a/endpoints-templates/Protocol.scala.ftl b/endpoints-templates/nu/zoom/dsl/Protocol.scala.ftl similarity index 100% rename from endpoints-templates/Protocol.scala.ftl rename to endpoints-templates/nu/zoom/dsl/Protocol.scala.ftl 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 dcfa86a..1ac2cb0 100644 --- a/parser/src/main/java/nu/zoom/dsl/freemarker/Generator.java +++ b/parser/src/main/java/nu/zoom/dsl/freemarker/Generator.java @@ -21,6 +21,7 @@ import nu.zoom.dsl.ast.DocumentNode; 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; @@ -50,17 +51,20 @@ public class Generator { } public List generate() throws IOException, TemplateException { - try (Stream files = Files.list(templatesDir)) { - List templates = files - .map(Path::getFileName) - .map(Path::toString) - .filter(p -> p.length() > TEMPLATE_EXTENSION_LENGTH && p.endsWith(TEMPLATE_EXTENSION) - ) - .toList(); + 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 (String template : templates) { - Path outpath = outputDir.resolve(outputFilenameFromTemplate(template)); - Template ftl = this.cfg.getTemplate(template); + 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); From 7e8aa018e95541affd65b07b1065484f287d834d Mon Sep 17 00:00:00 2001 From: Johan Maasing Date: Fri, 2 May 2025 09:25:27 +0200 Subject: [PATCH 05/10] Makes it possible to put templates in subdirectories --- README.md | 22 +++- endpoints-templates/endpoints.txt.ftl | 2 + .../nu/zoom/dsl/Codecs.scala.ftl | 2 +- .../nu/zoom/dsl/Endpoints.scala.ftl | 2 +- .../nu/zoom/dsl/Protocol.scala.ftl | 2 +- .../java/nu/zoom/dsl/ast/DocumentNode.java | 1 + .../java/nu/zoom/dsl/ast/GeneratorNode.java | 13 +++ .../src/main/java/nu/zoom/dsl/ast/Meta.java | 9 ++ .../nu/zoom/dsl/freemarker/Generator.java | 109 ++++++++++-------- 9 files changed, 109 insertions(+), 53 deletions(-) create mode 100644 parser/src/main/java/nu/zoom/dsl/ast/GeneratorNode.java create mode 100644 parser/src/main/java/nu/zoom/dsl/ast/Meta.java 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); + } } From e0922d5639f1f5a5e7a17b264439a10b92bfa9f4 Mon Sep 17 00:00:00 2001 From: Johan Maasing Date: Fri, 2 May 2025 09:25:27 +0200 Subject: [PATCH 06/10] Makes it possible to put templates in subdirectories --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7dc6cc1..3262cf7 100644 --- a/README.md +++ b/README.md @@ -309,10 +309,18 @@ public record TransitionNode(String message, String toState) { ### 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. +```java +public record Meta( + List templateDirectories, + String templateFile +) { } +``` +* `templateDirectories` 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 +``` + +* `templateFile` is the filename of the template (including the .ftl-ending) used to generate the output. \ No newline at end of file From 46da5c50195aeba0ddb71cb8625f8a6be1514984 Mon Sep 17 00:00:00 2001 From: Johan Maasing Date: Sun, 4 May 2025 09:41:16 +0200 Subject: [PATCH 07/10] needs testing --- endgen-maven-plugin/README.md | 8 ++ endgen-maven-plugin/pom.xml | 69 +++++++++++++ .../java/nu/zoom/dsl/maven/EndgenMojo.java | 64 +++++++++++++ .../java/nu/zoom/dsl/maven/MavenLogger.java | 17 ++++ .../src/main/java/nu/zoom/dsl/maven/Run.java | 52 ++++++++++ .../java/nu/zoom/dsl/cli/EndpointsCLI.java | 48 +++------- .../java/nu/zoom/dsl/run/EndgenException.java | 15 +++ .../nu/zoom/dsl/run/GeneratorException.java | 15 +++ .../src/main/java/nu/zoom/dsl/run/Logger.java | 5 + .../main/java/nu/zoom/dsl/run/NullLogger.java | 8 ++ .../java/nu/zoom/dsl/run/ParserException.java | 15 +++ .../zoom/dsl/{ast => run}/ParserWrapper.java | 5 +- .../src/main/java/nu/zoom/dsl/run/Runner.java | 96 +++++++++++++++++++ .../java/nu/zoom/dsl/run/StdoutLogger.java | 9 ++ .../nu/zoom/dsl/run/ValidationException.java | 15 +++ pom.xml | 1 + 16 files changed, 406 insertions(+), 36 deletions(-) create mode 100644 endgen-maven-plugin/README.md create mode 100644 endgen-maven-plugin/pom.xml create mode 100644 endgen-maven-plugin/src/main/java/nu/zoom/dsl/maven/EndgenMojo.java create mode 100644 endgen-maven-plugin/src/main/java/nu/zoom/dsl/maven/MavenLogger.java create mode 100644 endgen-maven-plugin/src/main/java/nu/zoom/dsl/maven/Run.java create mode 100644 parser/src/main/java/nu/zoom/dsl/run/EndgenException.java create mode 100644 parser/src/main/java/nu/zoom/dsl/run/GeneratorException.java create mode 100644 parser/src/main/java/nu/zoom/dsl/run/Logger.java create mode 100644 parser/src/main/java/nu/zoom/dsl/run/NullLogger.java create mode 100644 parser/src/main/java/nu/zoom/dsl/run/ParserException.java rename parser/src/main/java/nu/zoom/dsl/{ast => run}/ParserWrapper.java (93%) create mode 100644 parser/src/main/java/nu/zoom/dsl/run/Runner.java create mode 100644 parser/src/main/java/nu/zoom/dsl/run/StdoutLogger.java create mode 100644 parser/src/main/java/nu/zoom/dsl/run/ValidationException.java diff --git a/endgen-maven-plugin/README.md b/endgen-maven-plugin/README.md new file mode 100644 index 0000000..1e02921 --- /dev/null +++ b/endgen-maven-plugin/README.md @@ -0,0 +1,8 @@ +# References +## Maven + +https://maven.apache.org/plugins/maven-compiler-plugin/compile-mojo.html#generatedsourcesdirectory + +### For executing the plugin several times +See executions +https://maven.apache.org/guides/mini/guide-configuring-plugins.html \ No newline at end of file diff --git a/endgen-maven-plugin/pom.xml b/endgen-maven-plugin/pom.xml new file mode 100644 index 0000000..e9f42c5 --- /dev/null +++ b/endgen-maven-plugin/pom.xml @@ -0,0 +1,69 @@ + + + 4.0.0 + + + nu.zoom.dsl + endgen + 1.2-SNAPSHOT + + endgen-maven-plugin + maven-plugin + + + 3.15.1 + + + + org.apache.maven + maven-plugin-api + 3.9.9 + provided + + + + org.apache.maven.plugin-tools + maven-plugin-annotations + ${maven-plugin-tools.version} + provided + + + nu.zoom.dsl + parser + ${project.parent.version} + + + + + + + org.apache.maven.plugins + maven-plugin-plugin + ${maven-plugin-tools.version} + + + help-mojo + + helpmojo + + + + + + nu.zoom.dsl + endgen-maven-plugin + 1.2-SNAPSHOT + + + + ${project.build.sourceDirectory}/main/endgen-templates + ${project.build.sourceDirectory}/generated-sources/endgen endpoints-output + ${project.basedir}/../test01.endpoints + + + + + + + + \ No newline at end of file diff --git a/endgen-maven-plugin/src/main/java/nu/zoom/dsl/maven/EndgenMojo.java b/endgen-maven-plugin/src/main/java/nu/zoom/dsl/maven/EndgenMojo.java new file mode 100644 index 0000000..8d204aa --- /dev/null +++ b/endgen-maven-plugin/src/main/java/nu/zoom/dsl/maven/EndgenMojo.java @@ -0,0 +1,64 @@ +package nu.zoom.dsl.maven; + +import nu.zoom.dsl.run.Runner; +import nu.zoom.dsl.run.ValidationException; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; + +import java.io.File; +import java.util.Optional; + +@Mojo( + name = "endgen", + defaultPhase = LifecyclePhase.GENERATE_SOURCES +) +public class EndgenMojo extends AbstractMojo { + @Parameter(defaultValue = "${project.build.sourceDirectory}/main/endgen-templates") + File templates; + + @Parameter(defaultValue = "${project.build.outputDirectory}/generated-sources/endgen") + File output; + + @Parameter + File dsl; + + @Parameter + String parser; + + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + getLog().info("Running endgen"); + getLog().info("Using dsl: " + dsl); + try { + Runner.run( + optional(dsl).map(File::toPath).orElseThrow(), + optional(templates).map(File::toPath), + optional(output).map(File::toPath), + getParserType(parser), + new MavenLogger(getLog()) + ); + } catch (Exception e) { + throw new MojoExecutionException(e.getMessage(), e); + } + } + + private Optional getParserType(final String type) throws ValidationException { + if (type == null) { + return Optional.empty(); + } + try { + return Optional.of(Runner.ParserType.valueOf(type)); + } catch (IllegalArgumentException e) { + throw new ValidationException(e); + } + } + + private Optional optional(T arg) { + return arg == null ? Optional.empty() : Optional.of(arg); + } +} diff --git a/endgen-maven-plugin/src/main/java/nu/zoom/dsl/maven/MavenLogger.java b/endgen-maven-plugin/src/main/java/nu/zoom/dsl/maven/MavenLogger.java new file mode 100644 index 0000000..03b98be --- /dev/null +++ b/endgen-maven-plugin/src/main/java/nu/zoom/dsl/maven/MavenLogger.java @@ -0,0 +1,17 @@ +package nu.zoom.dsl.maven; + +import nu.zoom.dsl.run.Logger; +import org.apache.maven.plugin.logging.Log; + +public class MavenLogger implements Logger { + private final Log delegate; + + public MavenLogger(Log delegate) { + this.delegate = delegate; + } + + @Override + public void println(String message) { + this.delegate.debug(message); + } +} diff --git a/endgen-maven-plugin/src/main/java/nu/zoom/dsl/maven/Run.java b/endgen-maven-plugin/src/main/java/nu/zoom/dsl/maven/Run.java new file mode 100644 index 0000000..c8a0779 --- /dev/null +++ b/endgen-maven-plugin/src/main/java/nu/zoom/dsl/maven/Run.java @@ -0,0 +1,52 @@ +package nu.zoom.dsl.maven; + +import java.io.File; + +public class Run { + private File templates; + private File output; + private File dsl; + private String parser; + + public File getTemplates() { + return templates; + } + + public void setTemplates(File templates) { + this.templates = templates; + } + + public File getOutput() { + return output; + } + + public void setOutput(File output) { + this.output = output; + } + + public File getDsl() { + return dsl; + } + + public void setDsl(File dsl) { + this.dsl = dsl; + } + + public String getParser() { + return parser; + } + + public void setParser(String parser) { + this.parser = parser; + } + + @Override + public String toString() { + return "Run{" + + "templates=" + templates + + ", output=" + output + + ", dsl=" + dsl + + ", parser='" + parser + '\'' + + '}'; + } +} diff --git a/parser/src/main/java/nu/zoom/dsl/cli/EndpointsCLI.java b/parser/src/main/java/nu/zoom/dsl/cli/EndpointsCLI.java index e3d5794..8d79757 100644 --- a/parser/src/main/java/nu/zoom/dsl/cli/EndpointsCLI.java +++ b/parser/src/main/java/nu/zoom/dsl/cli/EndpointsCLI.java @@ -14,7 +14,7 @@ package nu.zoom.dsl.cli; import nu.zoom.dsl.ast.DocumentNode; -import nu.zoom.dsl.ast.ParserWrapper; +import nu.zoom.dsl.run.*; import nu.zoom.dsl.freemarker.Generator; import picocli.CommandLine; import picocli.CommandLine.Command; @@ -24,8 +24,8 @@ import picocli.CommandLine.Parameters; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.List; +import java.util.Optional; import java.util.concurrent.Callable; @Command( @@ -34,20 +34,16 @@ import java.util.concurrent.Callable; description = "Generate source code from an endpoints specification file." ) public class EndpointsCLI implements Callable { - public enum ParserType { - Endpoints, - States - } @SuppressWarnings("unused") @Parameters(index = "0", description = "The source endpoints DSL file.") private Path file; @SuppressWarnings("CanBeFinal") - @Option(names = {"-t", "--template"}, defaultValue = "endpoints-template", description = "The template directory. Default is ${DEFAULT-VALUE}") + @Option(names = {"-t", "--template"}, defaultValue = Runner.DEFAULT_TEMPLATE_DIRECTORY_NAME, description = "The template directory. Default is ${DEFAULT-VALUE}") private Path templateDir ; @SuppressWarnings("CanBeFinal") - @Option(names = {"-o", "--output"}, defaultValue = "endpoints-output", description = "The directory to write the generated code to. Default is ${DEFAULT-VALUE}") + @Option(names = {"-o", "--output"}, defaultValue = Runner.DEFAULT_OUTPUT_DIRECTORY_NAME, description = "The directory to write the generated code to. Default is ${DEFAULT-VALUE}") private Path outputDir ; @SuppressWarnings("unused") @@ -55,7 +51,7 @@ public class EndpointsCLI implements Callable { private Boolean verbose = false; @Option(names = {"-p", "--parser"}, description = "Force use of a specific parser instead of determining from filename. Valid values: ${COMPLETION-CANDIDATES}.") - private ParserType parser = null; + private Runner.ParserType parser = null; public static void main(String[] args) { int exitCode = new CommandLine(new EndpointsCLI()).execute(args); @@ -65,32 +61,14 @@ public class EndpointsCLI implements Callable { @Override public Integer call() { try { - validateTemplateDirectory(); - validateInputFile(); - validateOutputDirectory(); - verbose("Parsing: " + file.toAbsolutePath()); - if (parser == null) { - if (file.getFileName().toString().endsWith(".states")) { - parser = ParserType.States; - } - } - final DocumentNode rootNode ; - if (parser == ParserType.States) { - verbose("using state grammar.") ; - rootNode = ParserWrapper.parseStates(file); - } else { - verbose("using endpoints grammar.") ; - rootNode = ParserWrapper.parseEndpoints(file); - } - verbose("AST: " + rootNode); - verbose("Generating from templates in: " + templateDir.toAbsolutePath()); - Generator generator = new Generator(templateDir, rootNode, outputDir); - List generatedPaths = generator.generate(); - if (generatedPaths.isEmpty()) { - System.out.println("No generated paths found."); - } else { - generatedPaths.forEach(p -> verbose("Generated: " + p.toAbsolutePath())); - } + final Logger logger = this.verbose ? new StdoutLogger() : new NullLogger() ; + Runner.run( + this.file, + Optional.of(this.templateDir), + Optional.of(this.outputDir), + parser == null ? Optional.empty() : Optional.of(parser), + logger + ); return 0; } catch (Exception e) { System.err.println(e.getMessage()); diff --git a/parser/src/main/java/nu/zoom/dsl/run/EndgenException.java b/parser/src/main/java/nu/zoom/dsl/run/EndgenException.java new file mode 100644 index 0000000..7771e11 --- /dev/null +++ b/parser/src/main/java/nu/zoom/dsl/run/EndgenException.java @@ -0,0 +1,15 @@ +package nu.zoom.dsl.run; + +public abstract class EndgenException extends Exception { + public EndgenException(String message, Throwable cause) { + super(message, cause); + } + + public EndgenException(Throwable cause) { + super(cause); + } + + public EndgenException(String message) { + super(message); + } +} diff --git a/parser/src/main/java/nu/zoom/dsl/run/GeneratorException.java b/parser/src/main/java/nu/zoom/dsl/run/GeneratorException.java new file mode 100644 index 0000000..5157d97 --- /dev/null +++ b/parser/src/main/java/nu/zoom/dsl/run/GeneratorException.java @@ -0,0 +1,15 @@ +package nu.zoom.dsl.run; + +public class GeneratorException extends EndgenException { + public GeneratorException(String message) { + super(message); + } + + public GeneratorException(String message, Throwable cause) { + super(message, cause); + } + + public GeneratorException(Throwable cause) { + super(cause); + } +} diff --git a/parser/src/main/java/nu/zoom/dsl/run/Logger.java b/parser/src/main/java/nu/zoom/dsl/run/Logger.java new file mode 100644 index 0000000..80826d3 --- /dev/null +++ b/parser/src/main/java/nu/zoom/dsl/run/Logger.java @@ -0,0 +1,5 @@ +package nu.zoom.dsl.run; + +public interface Logger { + void println(String message); +} diff --git a/parser/src/main/java/nu/zoom/dsl/run/NullLogger.java b/parser/src/main/java/nu/zoom/dsl/run/NullLogger.java new file mode 100644 index 0000000..014f473 --- /dev/null +++ b/parser/src/main/java/nu/zoom/dsl/run/NullLogger.java @@ -0,0 +1,8 @@ +package nu.zoom.dsl.run; + +public class NullLogger implements Logger { + @Override + public void println(String message) { + + } +} diff --git a/parser/src/main/java/nu/zoom/dsl/run/ParserException.java b/parser/src/main/java/nu/zoom/dsl/run/ParserException.java new file mode 100644 index 0000000..b726384 --- /dev/null +++ b/parser/src/main/java/nu/zoom/dsl/run/ParserException.java @@ -0,0 +1,15 @@ +package nu.zoom.dsl.run; + +public class ParserException extends EndgenException { + public ParserException(String message) { + super(message); + } + + public ParserException(String message, Throwable cause) { + super(message, cause); + } + + public ParserException(Throwable cause) { + super(cause); + } +} diff --git a/parser/src/main/java/nu/zoom/dsl/ast/ParserWrapper.java b/parser/src/main/java/nu/zoom/dsl/run/ParserWrapper.java similarity index 93% rename from parser/src/main/java/nu/zoom/dsl/ast/ParserWrapper.java rename to parser/src/main/java/nu/zoom/dsl/run/ParserWrapper.java index 11a95fd..ce62d9c 100644 --- a/parser/src/main/java/nu/zoom/dsl/ast/ParserWrapper.java +++ b/parser/src/main/java/nu/zoom/dsl/run/ParserWrapper.java @@ -11,8 +11,11 @@ // 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 nu.zoom.dsl.ast; +package nu.zoom.dsl.run; +import nu.zoom.dsl.ast.DocumentNode; +import nu.zoom.dsl.ast.EndpointsVisitorTransformer; +import nu.zoom.dsl.ast.StatesVisitorTransformer; import nu.zoom.dsl.parser.*; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; diff --git a/parser/src/main/java/nu/zoom/dsl/run/Runner.java b/parser/src/main/java/nu/zoom/dsl/run/Runner.java new file mode 100644 index 0000000..ebf162b --- /dev/null +++ b/parser/src/main/java/nu/zoom/dsl/run/Runner.java @@ -0,0 +1,96 @@ +package nu.zoom.dsl.run; + +import freemarker.template.TemplateException; +import nu.zoom.dsl.ast.DocumentNode; +import nu.zoom.dsl.freemarker.Generator; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Optional; + +public final class Runner { + public static final String DEFAULT_TEMPLATE_DIRECTORY_NAME = "endpoints-template"; + public static final String DEFAULT_OUTPUT_DIRECTORY_NAME = "endpoints-output"; + + public static void run( + Path dsl, + Optional templates, + Optional output, + Optional maybeParser, + Logger logger + ) throws ValidationException, IOException, GeneratorException { + Path templatesDir = templates.orElse(Paths.get(DEFAULT_TEMPLATE_DIRECTORY_NAME)); + Path outputDir = output.orElse(Paths.get(DEFAULT_OUTPUT_DIRECTORY_NAME)); + + validateOutputDirectory(outputDir); + validateTemplateDirectory(templatesDir); + validateInputFile(dsl); + logger.println("Parsing: " + dsl.toAbsolutePath()); + + final ParserType parser = + maybeParser.orElseGet( + () -> { + if (dsl.getFileName().toString().endsWith(".states")) { + return ParserType.States; + } else { + return ParserType.Endpoints; + } + } + ); + + final DocumentNode rootNode; + if (parser == ParserType.States) { + logger.println("using state grammar."); + rootNode = ParserWrapper.parseStates(dsl); + } else { + logger.println("using endpoints grammar."); + rootNode = ParserWrapper.parseEndpoints(dsl); + } + logger.println("AST: " + rootNode); + logger.println("Generating from templates in: " + templatesDir.toAbsolutePath()); + Generator generator = new Generator(templatesDir, rootNode, outputDir); + List generatedPaths = null; + try { + generatedPaths = generator.generate(); + } catch (TemplateException e) { + throw new GeneratorException(e); + } + if (generatedPaths.isEmpty()) { + System.out.println("No generated paths found."); + } else { + generatedPaths.forEach(p -> logger.println("Generated: " + p.toAbsolutePath())); + } + } + + private static void validateOutputDirectory(Path outputDir) throws IOException, ValidationException { + if (Files.notExists(outputDir)) { + Files.createDirectories(outputDir); + } + if (!Files.isDirectory(outputDir)) { + throw new ValidationException("Output directory: '" + outputDir + " 'is not a directory."); + } + } + + private static void validateTemplateDirectory(Path templateDir) throws ValidationException { + if (!Files.isDirectory(templateDir)) { + throw new ValidationException("Template directory '" + templateDir + "' is not a directory."); + } + } + + private static void validateInputFile(Path file) throws ValidationException { + if (Files.notExists(file)) { + throw new ValidationException("Input file '" + file + "' does not exist."); + } + if (!Files.isReadable(file) || !Files.isRegularFile(file)) { + throw new ValidationException("Input file '" + file + "' is not a readable file."); + } + } + + public enum ParserType { + Endpoints, + States + } +} diff --git a/parser/src/main/java/nu/zoom/dsl/run/StdoutLogger.java b/parser/src/main/java/nu/zoom/dsl/run/StdoutLogger.java new file mode 100644 index 0000000..7b0b7d4 --- /dev/null +++ b/parser/src/main/java/nu/zoom/dsl/run/StdoutLogger.java @@ -0,0 +1,9 @@ +package nu.zoom.dsl.run; + +public class StdoutLogger implements Logger { + + @Override + public void println(String message) { + System.out.println(message); + } +} diff --git a/parser/src/main/java/nu/zoom/dsl/run/ValidationException.java b/parser/src/main/java/nu/zoom/dsl/run/ValidationException.java new file mode 100644 index 0000000..1627d72 --- /dev/null +++ b/parser/src/main/java/nu/zoom/dsl/run/ValidationException.java @@ -0,0 +1,15 @@ +package nu.zoom.dsl.run; + +public class ValidationException extends EndgenException { + public ValidationException(String message) { + super(message); + } + + public ValidationException(String message, Throwable cause) { + super(message, cause); + } + + public ValidationException(Throwable cause) { + super(cause); + } +} diff --git a/pom.xml b/pom.xml index 86744cc..cb060c8 100644 --- a/pom.xml +++ b/pom.xml @@ -65,6 +65,7 @@ parser endgen-dist + endgen-maven-plugin From 790be88cd763f0324f57207a065124c9684022cb Mon Sep 17 00:00:00 2001 From: Johan Maasing Date: Sun, 4 May 2025 15:04:47 +0200 Subject: [PATCH 08/10] Add sample project to test the maven plugin --- endgen-maven-plugin/README.md | 39 +++++++++-- endgen-maven-plugin/pom.xml | 36 +--------- .../java/nu/zoom/dsl/maven/EndgenMojo.java | 16 +++-- sample-maven/pom.xml | 70 +++++++++++++++++++ sample-maven/src/main/endgen/test01.endpoints | 28 ++++++++ sample-maven/src/main/endgen/test01.states | 21 ++++++ .../nu/zoom/dsl/sample/Endpoints.java.ftl | 22 ++++++ 7 files changed, 186 insertions(+), 46 deletions(-) create mode 100644 sample-maven/pom.xml create mode 100644 sample-maven/src/main/endgen/test01.endpoints create mode 100644 sample-maven/src/main/endgen/test01.states create mode 100644 sample-maven/src/main/endpoint-templates/nu/zoom/dsl/sample/Endpoints.java.ftl diff --git a/endgen-maven-plugin/README.md b/endgen-maven-plugin/README.md index 1e02921..3df592d 100644 --- a/endgen-maven-plugin/README.md +++ b/endgen-maven-plugin/README.md @@ -1,8 +1,35 @@ -# References -## Maven +# Configure -https://maven.apache.org/plugins/maven-compiler-plugin/compile-mojo.html#generatedsourcesdirectory +Add the following to your `pom.xml` -### For executing the plugin several times -See executions -https://maven.apache.org/guides/mini/guide-configuring-plugins.html \ No newline at end of file +```xml + + + + nu.zoom.dsl + endgen-maven-plugin + 1.2-SNAPSHOT + + + + endgen + + + ${project.basedir}/src/main/endpoint-templates + ${project.basedir}/src/main/endgen/test01.endpoints + + + + + + +``` + +Replace the `` with the latest published version of the endgen plugin. + +* `templates` should point to the template directory to use. +* `dsl` should be the file to generate code from. +* `output` can be used to specify the directory where the generated files are written. Default is `${project.build.directory}/generated-sources/endgen`. +* `parser` can be used to force the use of either the `Endpoints` or the `States` parser. Default is to determined by looking at the file ending of the dsl-file. + +If you have several DSL-files that you wish to generate from you can repeat the `` block with other configurations. \ No newline at end of file diff --git a/endgen-maven-plugin/pom.xml b/endgen-maven-plugin/pom.xml index e9f42c5..77bfe12 100644 --- a/endgen-maven-plugin/pom.xml +++ b/endgen-maven-plugin/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 @@ -33,37 +34,4 @@ ${project.parent.version} - - - - - org.apache.maven.plugins - maven-plugin-plugin - ${maven-plugin-tools.version} - - - help-mojo - - helpmojo - - - - - - nu.zoom.dsl - endgen-maven-plugin - 1.2-SNAPSHOT - - - - ${project.build.sourceDirectory}/main/endgen-templates - ${project.build.sourceDirectory}/generated-sources/endgen endpoints-output - ${project.basedir}/../test01.endpoints - - - - - - - \ No newline at end of file diff --git a/endgen-maven-plugin/src/main/java/nu/zoom/dsl/maven/EndgenMojo.java b/endgen-maven-plugin/src/main/java/nu/zoom/dsl/maven/EndgenMojo.java index 8d204aa..757eee5 100644 --- a/endgen-maven-plugin/src/main/java/nu/zoom/dsl/maven/EndgenMojo.java +++ b/endgen-maven-plugin/src/main/java/nu/zoom/dsl/maven/EndgenMojo.java @@ -17,23 +17,27 @@ import java.util.Optional; defaultPhase = LifecyclePhase.GENERATE_SOURCES ) public class EndgenMojo extends AbstractMojo { - @Parameter(defaultValue = "${project.build.sourceDirectory}/main/endgen-templates") + @Parameter( + name = "templates", + defaultValue = "${project.build.sourceDirectory}/main/endgen-templates" + ) File templates; - @Parameter(defaultValue = "${project.build.outputDirectory}/generated-sources/endgen") + @Parameter( + name = "output", + defaultValue = "${project.build.directory}/generated-sources/endgen" + ) File output; - @Parameter + @Parameter(name = "dsl", required = true) File dsl; - @Parameter + @Parameter(name = "parser") String parser; @Override public void execute() throws MojoExecutionException, MojoFailureException { - getLog().info("Running endgen"); - getLog().info("Using dsl: " + dsl); try { Runner.run( optional(dsl).map(File::toPath).orElseThrow(), diff --git a/sample-maven/pom.xml b/sample-maven/pom.xml new file mode 100644 index 0000000..99fdbab --- /dev/null +++ b/sample-maven/pom.xml @@ -0,0 +1,70 @@ + + + + 4.0.0 + + nu.zoom.dsl + sample-maven + 1.0-SNAPSHOT + jar + + + 21 + 21 + UTF-8 + + + + + ASF 2.0 + https://www.apache.org/licenses/LICENSE-2.0 + + + + + + Johan Maasing + johan@zoom.nu + + developer + + + + + + + + nu.zoom.dsl + endgen-maven-plugin + 1.2-SNAPSHOT + + + + endgen + + + ${project.basedir}/src/main/endpoint-templates + ${project.basedir}/src/main/endgen/test01.endpoints + + + + + + + + diff --git a/sample-maven/src/main/endgen/test01.endpoints b/sample-maven/src/main/endgen/test01.endpoints new file mode 100644 index 0000000..6f212ed --- /dev/null +++ b/sample-maven/src/main/endgen/test01.endpoints @@ -0,0 +1,28 @@ +/* + Copyright 2025 "Johan Maasing" + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + 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. +*/ + +{ + some: configvalue, + someother: value, + package: se.rutdev.senash +} + +/some/endpoint <- SomeType(foo:String) +Embedded(foo:Bar) +/some/other/endpoint <- (bar:Seq[Embedded]) +/yet/other/endpoint2 <- (bar2:Seq[AType]) -> NamedResponse(foo:Bar) +AType(data: java.util.List) +/yet/other/endpoint3 <- (bar2:Seq[AType]) -> (foo:Bar) diff --git a/sample-maven/src/main/endgen/test01.states b/sample-maven/src/main/endgen/test01.states new file mode 100644 index 0000000..3b9a67a --- /dev/null +++ b/sample-maven/src/main/endgen/test01.states @@ -0,0 +1,21 @@ +/* + Copyright 2025 "Johan Maasing" + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + 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. +*/ + +{ title: SomeNodes, package: nu.zoom.dsl.states } + +start(s:S) -> message(foo:foo) -> middle(foo:foo) , +middle -> selfmessage(bar:bar) -> middle(bar:bar), +middle -> message(bar:baz) -> end diff --git a/sample-maven/src/main/endpoint-templates/nu/zoom/dsl/sample/Endpoints.java.ftl b/sample-maven/src/main/endpoint-templates/nu/zoom/dsl/sample/Endpoints.java.ftl new file mode 100644 index 0000000..624c722 --- /dev/null +++ b/sample-maven/src/main/endpoint-templates/nu/zoom/dsl/sample/Endpoints.java.ftl @@ -0,0 +1,22 @@ +// Copyright 2025 "Johan Maasing" +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// 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. +<#list meta.templateDirectories>package<#items as dir>${dir}<#sep>.; + +class Endpoints() { +<#list endpoints as endpoint> + /* <#list endpoint.paths.paths><#items as segment>/${segment} */ + public void handle${endpoint.inputType?cap_first} + + +} \ No newline at end of file From 3e5befbb9a1a328917f90f87cc0153241882a9f0 Mon Sep 17 00:00:00 2001 From: Johan Maasing Date: Sun, 4 May 2025 15:05:56 +0200 Subject: [PATCH 09/10] [maven-release-plugin] prepare release v1.2 --- endgen-dist/pom.xml | 2 +- endgen-maven-plugin/pom.xml | 5 ++--- parser/pom.xml | 2 +- pom.xml | 4 ++-- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/endgen-dist/pom.xml b/endgen-dist/pom.xml index dda6922..c337f36 100644 --- a/endgen-dist/pom.xml +++ b/endgen-dist/pom.xml @@ -5,7 +5,7 @@ nu.zoom.dsl endgen - 1.2-SNAPSHOT + 1.2 endgen-dist diff --git a/endgen-maven-plugin/pom.xml b/endgen-maven-plugin/pom.xml index 77bfe12..37d2a72 100644 --- a/endgen-maven-plugin/pom.xml +++ b/endgen-maven-plugin/pom.xml @@ -1,12 +1,11 @@ - + 4.0.0 nu.zoom.dsl endgen - 1.2-SNAPSHOT + 1.2 endgen-maven-plugin maven-plugin diff --git a/parser/pom.xml b/parser/pom.xml index ba9d182..2d54120 100644 --- a/parser/pom.xml +++ b/parser/pom.xml @@ -20,7 +20,7 @@ nu.zoom.dsl endgen - 1.2-SNAPSHOT + 1.2 parser diff --git a/pom.xml b/pom.xml index cb060c8..c320d3a 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ nu.zoom.dsl endgen - 1.2-SNAPSHOT + 1.2 pom @@ -59,7 +59,7 @@ scm:git:https://codeberg.org/darkstar/endgen.git scm:git:ssh://git@vcs.zoom.nu:1122/zoom/endgen.git - admin-parent-1.1 + v1.2 From f17ff0c152cad254d879a42670819ecbb817849a Mon Sep 17 00:00:00 2001 From: Johan Maasing Date: Sun, 4 May 2025 15:05:59 +0200 Subject: [PATCH 10/10] [maven-release-plugin] prepare for next development iteration --- endgen-dist/pom.xml | 2 +- endgen-maven-plugin/pom.xml | 2 +- parser/pom.xml | 2 +- pom.xml | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/endgen-dist/pom.xml b/endgen-dist/pom.xml index c337f36..8a2fedb 100644 --- a/endgen-dist/pom.xml +++ b/endgen-dist/pom.xml @@ -5,7 +5,7 @@ nu.zoom.dsl endgen - 1.2 + 1.3-SNAPSHOT endgen-dist diff --git a/endgen-maven-plugin/pom.xml b/endgen-maven-plugin/pom.xml index 37d2a72..9974c25 100644 --- a/endgen-maven-plugin/pom.xml +++ b/endgen-maven-plugin/pom.xml @@ -5,7 +5,7 @@ nu.zoom.dsl endgen - 1.2 + 1.3-SNAPSHOT endgen-maven-plugin maven-plugin diff --git a/parser/pom.xml b/parser/pom.xml index 2d54120..67c6925 100644 --- a/parser/pom.xml +++ b/parser/pom.xml @@ -20,7 +20,7 @@ nu.zoom.dsl endgen - 1.2 + 1.3-SNAPSHOT parser diff --git a/pom.xml b/pom.xml index c320d3a..82a7a48 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ nu.zoom.dsl endgen - 1.2 + 1.3-SNAPSHOT pom @@ -59,7 +59,7 @@ scm:git:https://codeberg.org/darkstar/endgen.git scm:git:ssh://git@vcs.zoom.nu:1122/zoom/endgen.git - v1.2 + admin-parent-1.1