From 11857a00653cea01cd3229c044664c042902e4f6 Mon Sep 17 00:00:00 2001 From: Salathiel Genese Date: Mon, 23 Sep 2024 11:27:54 +0200 Subject: [PATCH] feat: #250 migrate from spring boot 2.7.3 to 3.3.1 and #269 update pipeline from java 17 to 21 (#271) * feat: upgrade to Spring Boot 3.3.1, Java from 17 to 21, get rid of Lombok, improve Java code * feat: nor arg ends up like --help arg * chore: from java 17 to 21 * chore: from java 17 to 21 * chore: delete unused dependencies spring-framework-bom 5.3.22 & spring-cloud-dependencies 2021.0.4 * docs: Update doc after migrating to Java 21 and Spring Boot 3.3.1 * docs: delete graalvm section and update readme * refactor: delete wildcard imports * fix: scan core package to get beans * fix: correct API tests by preventing bean methods to be proxied * docs: update CLI docs with feature related to #240 and querySelector option * fix: API & Desktop spring boot autoconf * docs: update API example * feat: add jsgenerator-desktop banner * docs: Add jsgenerator-desktop documentation * docs: update jsgenerator-cli example's command with the current version * refactoring: delete double columns before jsgenerator-cli launch command * docs: update API documentation with curl * docs: delete colon before jsgenerator-cli launch command * docs: update API documentation with curl * ci: Prevent Maven github action to run when changing Markdown files * fix: Correct Swagger dependency not working with Spring Boot 3 --------- Co-authored-by: Fanon Jupkwo --- .github/workflows/javadoc.yml | 4 +- .github/workflows/maven.yml | 8 +- README.api.md | 217 +++++++++++----- README.cli.md | 41 ++- README.desktop.md | 3 + README.md | 58 +++-- cli-build.sh | 16 -- illustrations/sample.html | 25 ++ .../screenshot_current_desktop_version.png | Bin 0 -> 30046 bytes jsgenerator-api/pom.xml | 4 + .../jsgenerator/core/Configuration.java | 72 ++++-- .../jsgenerator/core/Converter.java | 2 +- .../core/OutputStreamResolver.java | 2 +- .../core/VariableNameStrategy.java | 2 +- .../internal/InlineOutputStreamResolver.java | 2 +- .../internal/PathOutputStreamResolver.java | 2 +- .../internal/RandomVariableNameStrategy.java | 2 +- .../internal/StdinOutputStreamResolver.java | 2 +- .../TypeBasedVariableNameStrategy.java | 2 +- .../src/main/java/module-info.java | 2 +- jsgenerator-desktop/pom.xml | 170 ++----------- .../jsgenerator/desktop/HelloApplication.java | 23 -- .../jsgenerator/desktop/HelloController.java | 14 - .../autoconfigure/JsGeneratorDesktop.java | 62 +++++ .../desktop/controller/FxmlNavigator.java | 8 + .../desktop/controller/FxmlResolver.java | 10 + .../controller/HelloViewController.java | 34 +++ .../src/main/java/module-info.java | 26 +- .../src/main/resources/application.yml | 3 + .../src/main/resources/banner.txt | 9 + .../desktop/controller/hello-view.fxml | 18 ++ .../jsgenerator/desktop/hello-view.fxml | 16 -- jsgenerator-slim-api/pom.xml | 2 +- .../jsgenerator/api/JsGeneratorApi.java | 49 +++- .../jsgenerator/api/domain/InlineOptions.java | 26 +- .../api/domain/MultipartOptions.java | 14 +- .../jsgenerator/api/domain/Options.java | 94 ++++++- .../jsgenerator/api/domain/Output.java | 15 +- .../api/rest/ConvertController.java | 27 +- .../jsgenerator/api/rest/Reply.java | 36 +-- .../src/main/java/module-info.java | 6 +- .../jsgenerator/cli/JsGeneratorCli.java | 8 +- .../cli/internal/CommandDefault.java | 73 +++++- .../src/main/java/module-info.java | 1 - .../test/api/JsGeneratorApiTest.java | 84 +++--- .../api/helper/MultipartResultMatcher.java | 13 +- .../src/test/java/module-info.java | 8 +- .../jsgenerator/test/core/ConverterTest.java | 240 +++++++++--------- .../src/test/java/module-info.java | 2 +- pom.xml | 74 +----- 50 files changed, 908 insertions(+), 723 deletions(-) create mode 100644 README.desktop.md delete mode 100755 cli-build.sh create mode 100644 illustrations/sample.html create mode 100644 illustrations/screenshot_current_desktop_version.png delete mode 100644 jsgenerator-desktop/src/main/java/com/osscameroon/jsgenerator/desktop/HelloApplication.java delete mode 100644 jsgenerator-desktop/src/main/java/com/osscameroon/jsgenerator/desktop/HelloController.java create mode 100644 jsgenerator-desktop/src/main/java/com/osscameroon/jsgenerator/desktop/autoconfigure/JsGeneratorDesktop.java create mode 100644 jsgenerator-desktop/src/main/java/com/osscameroon/jsgenerator/desktop/controller/FxmlNavigator.java create mode 100644 jsgenerator-desktop/src/main/java/com/osscameroon/jsgenerator/desktop/controller/FxmlResolver.java create mode 100644 jsgenerator-desktop/src/main/java/com/osscameroon/jsgenerator/desktop/controller/HelloViewController.java create mode 100644 jsgenerator-desktop/src/main/resources/application.yml create mode 100644 jsgenerator-desktop/src/main/resources/banner.txt create mode 100644 jsgenerator-desktop/src/main/resources/com/osscameroon/jsgenerator/desktop/controller/hello-view.fxml delete mode 100644 jsgenerator-desktop/src/main/resources/com/osscameroon/jsgenerator/desktop/hello-view.fxml diff --git a/.github/workflows/javadoc.yml b/.github/workflows/javadoc.yml index 0235f811..c31cf4bb 100644 --- a/.github/workflows/javadoc.yml +++ b/.github/workflows/javadoc.yml @@ -15,11 +15,11 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: '17' + java-version: '21' # Given the fact that this is a multimodule project, build process will take long time so we activate caching # To know more: https://maven.apache.org/extensions/maven-build-cache-extension/cache.html cache: 'maven' diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 1b1e9aa6..f13d6d0e 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -6,8 +6,12 @@ name: Java CI with Maven on: push: branches: [ main ] + paths-ignore: + - '**.md' pull_request: branches: [ main ] + paths-ignore: + - '**.md' permissions: contents: read @@ -19,11 +23,11 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: '17' + java-version: '21' # Given the fact that this is a multimodule project, build process will take long time so we activate caching # To know more: https://maven.apache.org/extensions/maven-build-cache-extension/cache.html cache: 'maven' diff --git a/README.api.md b/README.api.md index d50ce812..bcd520bf 100644 --- a/README.api.md +++ b/README.api.md @@ -1,68 +1,5 @@ # API -Using [`httpie`](https://httpie.io/): -```shell -# You can also pass as many HTML content as you want -# Response will be of 'application/json' content type -http -vf :8080/convert \ - extension='.js' \ - contents[]='
' \ - contents[]='' - -HTTP/1.1 200 -Content-Type: application/json - -{ - "status": "SUCCESS" - "content": [ - { - "content": "const targetElement_000 = document.querySelector(`:root > body`);\r\n\r\n\r\nconst hr_000 = document.createElement('hr');\r\ntargetElement_000.appendChild(hr_000);\r\n", - "filename": "inline.0.js" - }, - { - "content": "const targetElement_001 = document.querySelector(`:root > body`);\r\n\r\n\r\nconst button_000 = document.createElement('button');\r\nbutton_000.setAttribute(`disabled`, `true`);\r\nconst text_000 = document.createTextNode(`click me, please :sob:`);\r\nbutton_000.appendChild(text_000);\r\ntargetElement_001.appendChild(button_000);\r\n", - "filename": "inline.1.js" - } - ] -} -``` - -Or, give the following two files contents: -> ```json -> { "extension": ".js" } // ./multipart-options.json -> ``` -> -> ```html -> -> -> -> -> ... -> ... -> ... -> ``` - -```shell -# You can call the API with multiple **files** and at most one **options** -# Response will be of 'multipart/form-data' content type -http -vf :8080/convert/files \ - 'files@./sample.html;type=multipart/form-data' \ - 'options@multipart-options.json;type=application/json' - -HTTP/1.1 200 -Content-Type: multipart/form-data;boundary=3N0wqEqnb7AC3WD8M1cYYG-vLfHDND_JdE90 - ---3N0wqEqnb7AC3WD8M1cYYG-vLfHDND_JdE90 -Content-Disposition: form-data; name="0.sample.html.js" -Content-Type: application/octet-stream -Content-Length: 4156 - -const targetElement_000 = document.querySelector(`:root > body`); -[... truncated for brievity] -``` - ---- - After starting the `jsgenerator-api` as described in the [README.md](./README.md), you can read: + OpenAPI spec. at: [http://localhost:8080/openapi.yaml](http://localhost:8080/openapi.yaml) @@ -79,10 +16,160 @@ Both accept options as follow: "pattern": "inline-filename-pattern", "variableNameStrategy": "TYPE_BASED", "variableDeclaration": "LET", - "extension": ".extension", + "extension": ".jsgenerator.js", + "commentConversionModeActivated": true, + "querySelectorAdded": true, "contents": [ "string" ] } ``` -> **NOTE:** The `"content"` field is mandatory for `POST /convert` and forbidden for `POST /convert/files` \ No newline at end of file +> **NOTE:** The `"contents"` field is mandatory for `POST /convert` and forbidden for `POST /convert/files` + + +--- + +Using [`curl`](https://curl.se/): + ++ `POST /convert` +```shell +# You can also pass as many HTML content as you want +# Response will be of 'application/json' content type +curl -H 'content-type: application/json' -X POST --data '{"contents": ["
js-jsgenerator
"]}' http://localhost:8080/convert + +#Response +{"content":[{"filename":"inline.0.jsgenerator.js","content":"let targetElement_001 = document.querySelector(`:root > body`);\r\n\r\n\r\nlet div_001 = document.createElement('div');\r\nlet text_001 = document.createTextNode(`js-generator`);\r\ndiv_001.appendChild(text_001);\r\ntargetElement_001.appendChild(div_001);\r\n"}],"status":"SUCCESS"} +``` + ++ `POST /convert/files` +```shell +# You can call the API with multiple **files** and at most one **options** +# Response will be of 'multipart/form-data' content type +curl -s -X POST -H 'content-type: multipart/form-data' -F files=@illustrations/sample.html -F "options={ \"querySelectorAdded\": true, \"variableDeclaration\": \"VAR\" }; type=application/json" http://localhost:8080/convert/files + +# -s flag is added in order to prevent curl to mix response and progress meter +#if not added, this will happen: 100 5280 100 4275 100 1005 117k 28194 --:--:-- --:--:-- --:--:-- 147kment.createTextNode(` `); + +#Response + +--d2a-7NlH3rlmcFC3loiJxDxom6iojCunhkzzH +Content-Disposition: form-data; name="inline.0.jsgenerator.js" +Content-Type: application/octet-stream +Content-Length: 4069 + +var targetElement_001 = document.querySelector(`:root > body`); + + +var html_001 = document.createElement('html'); +var text_001 = document.createTextNode(` `); +html_001.appendChild(text_001); + +var head_001 = document.createElement('head'); +var text_002 = document.createTextNode(` `); +head_001.appendChild(text_002); + +var meta_001 = document.createElement('meta'); +meta_001.setAttribute(`charset`, `utf-8`); +head_001.appendChild(meta_001); +var text_003 = document.createTextNode(` `); +head_001.appendChild(text_003); + +var title_001 = document.createElement('title'); +var text_004 = document.createTextNode(`Sample`); +title_001.appendChild(text_004); +head_001.appendChild(title_001); +var text_005 = document.createTextNode(` `); +head_001.appendChild(text_005); + +var link_001 = document.createElement('link'); +link_001.setAttribute(`rel`, `stylesheet`); +link_001.setAttribute(`href`, ``); +head_001.appendChild(link_001); +var text_006 = document.createTextNode(` `); +head_001.appendChild(text_006); +html_001.appendChild(head_001); +var text_007 = document.createTextNode(` `); +html_001.appendChild(text_007); + +var body_001 = document.createElement('body'); +var text_008 = document.createTextNode(` `); +body_001.appendChild(text_008); + +var div_001 = document.createElement('div'); +div_001.setAttribute(`id`, `container`); +var text_009 = document.createTextNode(` `); +div_001.appendChild(text_009); + +var div_002 = document.createElement('div'); +div_002.setAttribute(`id`, `header`); +var text_010 = document.createTextNode(` `); +div_002.appendChild(text_010); + +var h1_001 = document.createElement('h1'); +var text_011 = document.createTextNode(`Sample`); +h1_001.appendChild(text_011); +div_002.appendChild(h1_001); +var text_012 = document.createTextNode(` `); +div_002.appendChild(text_012); + +var img_001 = document.createElement('img'); +img_001.setAttribute(`src`, `kanye.jpg`); +img_001.setAttribute(`alt`, `kanye`); +div_002.appendChild(img_001); +var text_013 = document.createTextNode(` `); +div_002.appendChild(text_013); +div_001.appendChild(div_002); +var text_014 = document.createTextNode(` `); +div_001.appendChild(text_014); + +var div_003 = document.createElement('div'); +div_003.setAttribute(`id`, `main`); +var text_015 = document.createTextNode(` `); +div_003.appendChild(text_015); + +var h2_001 = document.createElement('h2'); +var text_016 = document.createTextNode(`Main`); +h2_001.appendChild(text_016); +div_003.appendChild(h2_001); +var text_017 = document.createTextNode(` `); +div_003.appendChild(text_017); + +var p_001 = document.createElement('p'); +var text_018 = document.createTextNode(`This is the main content.`); +p_001.appendChild(text_018); +div_003.appendChild(p_001); +var text_019 = document.createTextNode(` `); +div_003.appendChild(text_019); + +var img_002 = document.createElement('img'); +img_002.setAttribute(`src`, ``); +img_002.setAttribute(`alt`, ``); +div_003.appendChild(img_002); +var text_020 = document.createTextNode(` `); +div_003.appendChild(text_020); +div_001.appendChild(div_003); +var text_021 = document.createTextNode(` `); +div_001.appendChild(text_021); + +var div_004 = document.createElement('div'); +div_004.setAttribute(`id`, `footer`); +var text_022 = document.createTextNode(` `); +div_004.appendChild(text_022); + +var p_002 = document.createElement('p'); +var text_023 = document.createTextNode(`Copyright - 2019`); +p_002.appendChild(text_023); +div_004.appendChild(p_002); +var text_024 = document.createTextNode(` `); +div_004.appendChild(text_024); +div_001.appendChild(div_004); +var text_025 = document.createTextNode(` `); +div_001.appendChild(text_025); +body_001.appendChild(div_001); +var text_026 = document.createTextNode(` `); +body_001.appendChild(text_026); +html_001.appendChild(body_001); +targetElement_001.appendChild(html_001); + +--d2a-7NlH3rlmcFC3loiJxDxom6iojCunhkzzH-- +``` diff --git a/README.cli.md b/README.cli.md index 15aed949..59c234c0 100644 --- a/README.cli.md +++ b/README.cli.md @@ -1,18 +1,18 @@ # Command Line Interface ```shell -let targetElement_000 = document.querySelector(`:root > body`); +let targetElement_001 = document.querySelector(`:root > body`); -let div_000 = document.createElement('div'); -let text_000 = document.createTextNode(`I am a `); -div_000.appendChild(text_000); +let div_001 = document.createElement('div'); +let text_001 = document.createTextNode(`I am a `); +div_001.appendChild(text_001); -let strong_000 = document.createElement('strong'); -let text_001 = document.createTextNode(`tea pot`); -strong_000.appendChild(text_001); -div_000.appendChild(strong_000); -targetElement_000.appendChild(div_000); +let strong_001 = document.createElement('strong'); +let text_002 = document.createTextNode(`tea pot`); +strong_001.appendChild(text_002); +div_001.appendChild(strong_001); +targetElement_001.appendChild(div_001); ``` --- @@ -20,7 +20,8 @@ targetElement_000.appendChild(div_000); `jsgenerator` has several options that can be used in a console here is an example of use below ```text -Usage: jsgenerator [-htV] [-e=] [--inline-pattern=] +Usage: jsgenerator [-chtV] [-qs] [-e=] + [--inline-pattern=] [-k=] [--path-pattern=] [-s=] [--stdin-pattern=] @@ -28,6 +29,7 @@ Usage: jsgenerator [-htV] [-e=] [--inline-pattern=] tegy>] [-i=...]... [...] Translating files, stdin or inline from HTML to JS [...] file paths to translate content, parsed as HTML + -c, --comment optional comments -e, --ext= output files' extension -h, --help Show this help message and exit. -i, --inline=... @@ -38,6 +40,23 @@ Translating files, stdin or inline from HTML to JS variable declaration keyword --path-pattern= pattern for path-based output filenames + -qs, --query-selector + What the browser renders depends on whether "document. + querySelector(':root > body')" is added to the + output. If added, the browser will render the + output successfully, it is useful for debugging + purpose, + to verify that the js output matches what the + html input does. + If not, if the user tries to run the output as + it is then the browser will not be able to render, + it will show a blank page. + So, it depends on what the user wants to do with + the output. + "https://jsfiddle.net/", "https://codepen. + io/pen/" and Browser Console help to give a quick + feedback. + -s, --selector= Target element selector --stdin-pattern= @@ -46,4 +65,4 @@ Translating files, stdin or inline from HTML to JS -V, --version Print version information and exit. --variable-name-generation-strategy= Variable names generation strategy -``` \ No newline at end of file +``` diff --git a/README.desktop.md b/README.desktop.md new file mode 100644 index 00000000..3554a3db --- /dev/null +++ b/README.desktop.md @@ -0,0 +1,3 @@ +> Screenshot of the current desktop version: +> +> ![Screenshot of the current desktop version](illustrations/screenshot_current_desktop_version.png) diff --git a/README.md b/README.md index e6218842..e1febd94 100644 --- a/README.md +++ b/README.md @@ -44,23 +44,11 @@ We would like to give credit to [jsoup](https://jsoup.org/) / [jsoup GitHub Repo ## Requirements -+ JDK 17 - > **Because we use modern JavaFX** - > - > **NOTE:** For native build (CLI, for eg.), we use GraalVM with JDK 17. - > - > Recent versions of GraalVM are not bundling `native-image` CLI by default. - > We are required to install is manually, by running: - > ```shell - > # Where `gu` is an executable bundled with GraalVM - > gu install native-image - > ``` ++ JDK 21 + Maven 4 > Because of its unique features over maven 3: > namely, multi module dependency resolution under common parent, when running a maven goal only on some child -+ Spring 5.3.22 - > A framework to bootstrap dependency injection and inversion of control for our modules -+ Spring Boot 2.7.3 ++ Spring Boot 3.3.1 > Leverage convention over configuration and autoconfiguration discovery to enforce consistent a behaviour > throughout our frontends @@ -80,13 +68,14 @@ js-generator: ## Architecture | THE MODULE | ITS CONTENT && DEPENDENCIES | PACKAGING | -|------------------------------------|-------------------------------------|-----------| -| js-generator | Bill of Material, global properties | POM | -| jsgenerator-core | Core API, Spring Boot auto-conf | JAR | -| jsgenerator-slim-api | jsgenerator-core, spring-web | JAR | -| jsgenerator-slim-cli | jsgenerator-core, picocli | JAR | -| [jsgenerator-api](./README.api.md) | jsgenerator-slim-api | FAT JAR | -| [jsgenerator-cli](./README.cli.md) | jsgenerator-slim-cli | FAT JAR | +|------------------------------------|-------------------------------------|-------| +| js-generator | Bill of Material, global properties | POM | +| jsgenerator-core | Core API, Spring Boot auto-conf | JAR | +| jsgenerator-slim-api | jsgenerator-core, spring-web | JAR | +| jsgenerator-slim-cli | jsgenerator-core, picocli | JAR | +| [jsgenerator-api](./README.api.md) | jsgenerator-slim-api | FAT JAR | +| [jsgenerator-cli](./README.cli.md) | jsgenerator-slim-cli | FAT JAR | +| [jsgenerator-desktop](./README.desktop.md) | jsgenerator-core, javafx-fxml | JAR | > **NOTE:** FAT JAR packaged modules are mere wrappers around slim modules. The separation is important because then, > the test modules can use slim JARs as dependencies, unlike FAT JARs. This has to do with how "normal" vs. FAT JARs @@ -113,30 +102,43 @@ mvn clean test > > ![](illustrations/intellij-maven-runner-configuration.png) -API Server +API Server : [jsgenerator-api](./README.api.md) ```shell # After starting the server, visit http://localhost:8080 mvn --also-make --projects jsgenerator-api clean spring-boot:run ``` -Command Line Interface (CLI) +Command Line Interface (CLI) : [jsgenerator-cli](./README.cli.md) ```shell # After reading the help, play out with different CLI options mvn --also-make --projects jsgenerator-cli clean spring-boot:run -Dspring-boot.run.arguments=--help # For example: -mvn --also-make --projects :jsgenerator-cli clean spring-boot:run \ - -Dspring-boot.run.arguments="--tty --inline '
I am a tea pot
'" +mvn --also-make --projects jsgenerator-cli clean spring-boot:run -Dspring-boot.run.arguments="--tty --inline '
I am a tea pot
'" + +# It's also possible to create the jar first +mvn clean package + +# then run the following commands and replace {version} by the current one (0.0.1-SNAPSHOT at this time) +java -jar jsgenerator-cli/target/jsgenerator-cli-{version}.jar # java -jar jsgenerator-cli/target/jsgenerator-cli-0.0.1-SNAPSHOT.jar --help +java -jar jsgenerator-cli/target/jsgenerator-cli-{version}.jar --tty --inline '
I am a tea pot
' +``` + +Desktop : [jsgenerator-desktop](./README.desktop.md) +```shell +# Create the jar first +mvn clean package + +# then run this command and replace {version} by the current one (0.0.1-SNAPSHOT at this time) +java -jar jsgenerator-desktop/target/jsgenerator-desktop-{version}.jar # java -jar jsgenerator-desktop/target/jsgenerator-desktop-0.0.1-SNAPSHOT.jar ``` + ## Packaging ```shell # Will compile all the modules into JAR (or FAT JAR - see the table above) mvn clean package - -# Additionally, build CLI into native executable (require GraalVM - see requirements above) -./cli-build.sh ``` # Contribute diff --git a/cli-build.sh b/cli-build.sh deleted file mode 100755 index a9fca043..00000000 --- a/cli-build.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env sh -set -euxo - -_NATIVE_DIRECTORY="$(mktemp --directory --tmpdir="$(dirname "$(realpath "$0")")/jsgenerator-cli/target" native-XXXXXX)" -cat "$(dirname "$(realpath "$0")")/jsgenerator-cli/target/"*.original > "${_NATIVE_DIRECTORY}/jsgenerator-cli.jar" - -unzip ./jsgenerator-cli/target/*.jar -d "${_NATIVE_DIRECTORY}/" -_CLASSPATH="$(find "${_NATIVE_DIRECTORY}/BOOT-INF/lib" | tr '\n' ':')" -_CLASSPATH="${_NATIVE_DIRECTORY}/jsgenerator-cli.jar:${_CLASSPATH}:${_NATIVE_DIRECTORY}/BOOT-INF/classes" - -cp -R "${_NATIVE_DIRECTORY}/META-INF" "${_NATIVE_DIRECTORY}/BOOT-INF/classes" -native-image \ - "-H:Name=${1:-jsgenerator}" \ - --class-path "${_CLASSPATH}" \ - --module-path "${_CLASSPATH}" \ - --module com.osscameroon.jsgenerator.cli/com.osscameroon.jsgenerator.cli.JsGeneratorCli diff --git a/illustrations/sample.html b/illustrations/sample.html new file mode 100644 index 00000000..459b4962 --- /dev/null +++ b/illustrations/sample.html @@ -0,0 +1,25 @@ + + + + + + Sample + + + +
+ +
+

Main

+

This is the main content.

+ +
+ +
+ + \ No newline at end of file diff --git a/illustrations/screenshot_current_desktop_version.png b/illustrations/screenshot_current_desktop_version.png new file mode 100644 index 0000000000000000000000000000000000000000..8368e76160b2a6393338fb1538ba6bdf12c68284 GIT binary patch literal 30046 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 n?^(w3?|1wE + + org.graalvm.buildtools + native-maven-plugin + org.springframework.boot spring-boot-maven-plugin diff --git a/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/Configuration.java b/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/Configuration.java index ba27273d..34feb9f9 100644 --- a/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/Configuration.java +++ b/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/Configuration.java @@ -1,17 +1,9 @@ package com.osscameroon.jsgenerator.core; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - import static com.osscameroon.jsgenerator.core.VariableDeclaration.LET; import static com.osscameroon.jsgenerator.core.VariableNameStrategy.ofTypeBased; -@Data -@NoArgsConstructor -@AllArgsConstructor public class Configuration { - private static final String ROOT_BODY = ":root > body"; private String targetElementSelector = ROOT_BODY; @@ -30,36 +22,62 @@ public class Configuration { private VariableDeclaration variableDeclaration = LET; private VariableNameStrategy variableNameStrategy = ofTypeBased(); - public Configuration(final VariableDeclaration variableDeclaration) { - this(variableDeclaration, ofTypeBased()); + public Configuration() { + } + + public Configuration(VariableDeclaration variableDeclaration, + boolean querySelectorAdded, + boolean commentConversionModeActivated) { + this.querySelectorAdded = querySelectorAdded; + this.variableDeclaration = variableDeclaration; + this.commentConversionModeActivated = commentConversionModeActivated; } - public Configuration(final VariableDeclaration variableDeclaration, final boolean querySelectorAdded, final boolean commentConversionModeActivated) { - this(variableDeclaration, ofTypeBased(), querySelectorAdded, commentConversionModeActivated); + public Configuration(VariableDeclaration variableDeclaration, + boolean querySelectorAdded) { + this.querySelectorAdded = querySelectorAdded; + this.variableDeclaration = variableDeclaration; } - public Configuration(final VariableDeclaration variableDeclaration, final boolean querySelectorAdded) { - this(variableDeclaration, ofTypeBased(), querySelectorAdded, true); + public Configuration(VariableDeclaration variableDeclaration, + VariableNameStrategy variableNameStrategy, + boolean querySelectorAdded, + boolean commentConversionModeActivated) { + this.querySelectorAdded = querySelectorAdded; + this.variableDeclaration = variableDeclaration; + this.variableNameStrategy = variableNameStrategy; + this.commentConversionModeActivated = commentConversionModeActivated; } + public Configuration(String targetElementSelector, + boolean querySelectorAdded, + boolean commentConversionModeActivated, + VariableDeclaration variableDeclaration, + VariableNameStrategy variableNameStrategy) { + this.querySelectorAdded = querySelectorAdded; + this.variableDeclaration = variableDeclaration; + this.variableNameStrategy = variableNameStrategy; + this.targetElementSelector = targetElementSelector; + this.commentConversionModeActivated = commentConversionModeActivated; + } + + public String getTargetElementSelector() { + return targetElementSelector; + } - public Configuration(final String targetElementSelector, - final VariableDeclaration variableDeclaration) { - this(targetElementSelector, true, true, variableDeclaration, ofTypeBased()); + public boolean isQuerySelectorAdded() { + return querySelectorAdded; } - public Configuration(final String targetElementSelector, - final VariableDeclaration variableDeclaration, final boolean querySelectorAdded, final boolean commentConversionModeActivated) { - this(targetElementSelector, querySelectorAdded, commentConversionModeActivated, variableDeclaration, ofTypeBased()); + public boolean isCommentConversionModeActivated() { + return commentConversionModeActivated; } - public Configuration(final VariableDeclaration variableDeclaration, - final VariableNameStrategy variableNameStrategy) { - this(ROOT_BODY, true, true, variableDeclaration, variableNameStrategy); + public VariableDeclaration getVariableDeclaration() { + return variableDeclaration; } - public Configuration(final VariableDeclaration variableDeclaration, - final VariableNameStrategy variableNameStrategy, final boolean querySelectorAdded, final boolean commentConversionModeActivated) { - this(ROOT_BODY, querySelectorAdded, commentConversionModeActivated, variableDeclaration, variableNameStrategy); + public VariableNameStrategy getVariableNameStrategy() { + return variableNameStrategy; } -} \ No newline at end of file +} diff --git a/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/Converter.java b/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/Converter.java index bcc10711..74d9fc60 100644 --- a/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/Converter.java +++ b/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/Converter.java @@ -1,7 +1,7 @@ package com.osscameroon.jsgenerator.core; import com.osscameroon.jsgenerator.core.internal.ConverterDefault; -import lombok.NonNull; +import org.springframework.lang.NonNull; import java.io.IOException; import java.io.InputStream; diff --git a/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/OutputStreamResolver.java b/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/OutputStreamResolver.java index 41d48185..17cf928a 100644 --- a/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/OutputStreamResolver.java +++ b/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/OutputStreamResolver.java @@ -3,7 +3,7 @@ import com.osscameroon.jsgenerator.core.internal.InlineOutputStreamResolver; import com.osscameroon.jsgenerator.core.internal.PathOutputStreamResolver; import com.osscameroon.jsgenerator.core.internal.StdinOutputStreamResolver; -import lombok.NonNull; +import org.springframework.lang.NonNull; import java.util.Map; diff --git a/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/VariableNameStrategy.java b/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/VariableNameStrategy.java index 42b2ea1d..c74871a6 100644 --- a/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/VariableNameStrategy.java +++ b/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/VariableNameStrategy.java @@ -2,7 +2,7 @@ import com.osscameroon.jsgenerator.core.internal.RandomVariableNameStrategy; import com.osscameroon.jsgenerator.core.internal.TypeBasedVariableNameStrategy; -import lombok.NonNull; +import org.springframework.lang.NonNull; @FunctionalInterface public interface VariableNameStrategy { diff --git a/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/internal/InlineOutputStreamResolver.java b/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/internal/InlineOutputStreamResolver.java index 84f5d732..70fe06a2 100644 --- a/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/internal/InlineOutputStreamResolver.java +++ b/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/internal/InlineOutputStreamResolver.java @@ -1,7 +1,7 @@ package com.osscameroon.jsgenerator.core.internal; import com.osscameroon.jsgenerator.core.OutputStreamResolver; -import lombok.NonNull; +import org.springframework.lang.NonNull; import java.util.Map; diff --git a/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/internal/PathOutputStreamResolver.java b/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/internal/PathOutputStreamResolver.java index 2819e5ec..c30b2537 100644 --- a/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/internal/PathOutputStreamResolver.java +++ b/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/internal/PathOutputStreamResolver.java @@ -1,7 +1,7 @@ package com.osscameroon.jsgenerator.core.internal; import com.osscameroon.jsgenerator.core.OutputStreamResolver; -import lombok.NonNull; +import org.springframework.lang.NonNull; import java.util.Map; diff --git a/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/internal/RandomVariableNameStrategy.java b/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/internal/RandomVariableNameStrategy.java index 730a78c6..f41b2f15 100644 --- a/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/internal/RandomVariableNameStrategy.java +++ b/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/internal/RandomVariableNameStrategy.java @@ -1,7 +1,7 @@ package com.osscameroon.jsgenerator.core.internal; import com.osscameroon.jsgenerator.core.VariableNameStrategy; -import lombok.NonNull; +import org.springframework.lang.NonNull; import static java.util.UUID.randomUUID; diff --git a/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/internal/StdinOutputStreamResolver.java b/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/internal/StdinOutputStreamResolver.java index 6d2a2ffe..5f214e95 100644 --- a/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/internal/StdinOutputStreamResolver.java +++ b/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/internal/StdinOutputStreamResolver.java @@ -1,7 +1,7 @@ package com.osscameroon.jsgenerator.core.internal; import com.osscameroon.jsgenerator.core.OutputStreamResolver; -import lombok.NonNull; +import org.springframework.lang.NonNull; import java.util.Map; diff --git a/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/internal/TypeBasedVariableNameStrategy.java b/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/internal/TypeBasedVariableNameStrategy.java index 143b6cbd..f5f5de2f 100644 --- a/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/internal/TypeBasedVariableNameStrategy.java +++ b/jsgenerator-core/src/main/java/com/osscameroon/jsgenerator/core/internal/TypeBasedVariableNameStrategy.java @@ -1,7 +1,7 @@ package com.osscameroon.jsgenerator.core.internal; import com.osscameroon.jsgenerator.core.VariableNameStrategy; -import lombok.NonNull; +import org.springframework.lang.NonNull; import java.util.HashMap; import java.util.Map; diff --git a/jsgenerator-core/src/main/java/module-info.java b/jsgenerator-core/src/main/java/module-info.java index 6de056e4..0d74b538 100644 --- a/jsgenerator-core/src/main/java/module-info.java +++ b/jsgenerator-core/src/main/java/module-info.java @@ -4,10 +4,10 @@ opens com.osscameroon.jsgenerator.core.autoconfigure; - requires lombok; requires org.jsoup; requires spring.boot; requires spring.context; requires spring.boot.autoconfigure; + requires spring.core; } diff --git a/jsgenerator-desktop/pom.xml b/jsgenerator-desktop/pom.xml index 0c7d9e6e..b7cb3f75 100644 --- a/jsgenerator-desktop/pom.xml +++ b/jsgenerator-desktop/pom.xml @@ -9,179 +9,45 @@ ${revision} - 4.0.0 - jsgenerator-desktop - jsgenerator-desktop - 17.0.2 - 0.0.8 - com.osscameroon.jsgenerator.desktop.HelloApplication + com.osscameroon.jsgenerator.desktop.autoconfigure.JsGeneratorDesktop - - - - org.springframework.boot - spring-boot-starter - - com.osscameroon jsgenerator-core - - - - org.openjfx - javafx-controls - ${javafx.version} - org.openjfx javafx-fxml - ${javafx.version} - - - org.openjfx - javafx-web - ${javafx.version} - - org.controlsfx - controlsfx - 11.1.1 - - - com.dlsc.formsfx - formsfx-core - 11.5.0 - - - org.openjfx - * - - - - - net.synedra - validatorfx - 0.4.0 - - - org.openjfx - * - - - - - org.kordamp.ikonli - ikonli-javafx - 12.3.1 - - - org.kordamp.bootstrapfx - bootstrapfx-core - 0.4.0 - - - eu.hansolo - tilesfx - 17.1.9 - - - org.openjfx - * - - - - - - - - eu.hansolo.fx - countries - 17.0.22 - - - - - - - - eu.hansolo.fx - heatmap - 17.0.9 - - - - - - - eu.hansolo - toolboxfx - 17.0.28 - - - - - - - - eu.hansolo - toolbox - 17.0.22 - - - - - - - - org.openjfx - javafx-swing - 20-ea+4 - - - - - org.openjfx - javafx-maven-plugin - ${javafx.plugin.version} - - - - default-cli - - ${mainClass} - app - app - app - true - true - true - - - + org.graalvm.buildtools + native-maven-plugin + + + org.springframework.boot + spring-boot-maven-plugin + + false + + + + org.apache.maven.plugins + maven-compiler-plugin + + 22 + 22 + diff --git a/jsgenerator-desktop/src/main/java/com/osscameroon/jsgenerator/desktop/HelloApplication.java b/jsgenerator-desktop/src/main/java/com/osscameroon/jsgenerator/desktop/HelloApplication.java deleted file mode 100644 index 95ea741e..00000000 --- a/jsgenerator-desktop/src/main/java/com/osscameroon/jsgenerator/desktop/HelloApplication.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.osscameroon.jsgenerator.desktop; - -import javafx.application.Application; -import javafx.fxml.FXMLLoader; -import javafx.scene.Scene; -import javafx.stage.Stage; - -import java.io.IOException; - -public class HelloApplication extends Application { - @Override - public void start(Stage stage) throws IOException { - FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml")); - Scene scene = new Scene(fxmlLoader.load(), 320, 240); - stage.setTitle("Hello!"); - stage.setScene(scene); - stage.show(); - } - - public static void main(String[] args) { - launch(); - } -} \ No newline at end of file diff --git a/jsgenerator-desktop/src/main/java/com/osscameroon/jsgenerator/desktop/HelloController.java b/jsgenerator-desktop/src/main/java/com/osscameroon/jsgenerator/desktop/HelloController.java deleted file mode 100644 index 7e3cfb26..00000000 --- a/jsgenerator-desktop/src/main/java/com/osscameroon/jsgenerator/desktop/HelloController.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.osscameroon.jsgenerator.desktop; - -import javafx.fxml.FXML; -import javafx.scene.control.Label; - -public class HelloController { - @FXML - private Label welcomeText; - - @FXML - protected void onHelloButtonClick() { - welcomeText.setText("Welcome to JavaFX Application!"); - } -} \ No newline at end of file diff --git a/jsgenerator-desktop/src/main/java/com/osscameroon/jsgenerator/desktop/autoconfigure/JsGeneratorDesktop.java b/jsgenerator-desktop/src/main/java/com/osscameroon/jsgenerator/desktop/autoconfigure/JsGeneratorDesktop.java new file mode 100644 index 00000000..8af9795d --- /dev/null +++ b/jsgenerator-desktop/src/main/java/com/osscameroon/jsgenerator/desktop/autoconfigure/JsGeneratorDesktop.java @@ -0,0 +1,62 @@ +package com.osscameroon.jsgenerator.desktop.autoconfigure; + +import com.osscameroon.jsgenerator.core.autoconfigure.JsGeneratorCoreAutoconfigure; +import com.osscameroon.jsgenerator.desktop.controller.FxmlNavigator; +import com.osscameroon.jsgenerator.desktop.controller.FxmlResolver; +import com.osscameroon.jsgenerator.desktop.controller.HelloViewController; +import javafx.application.Application; +import javafx.fxml.FXMLLoader; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.stage.Stage; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Lazy; +import org.springframework.core.io.ClassPathResource; + +import java.io.IOException; + +@ImportAutoConfiguration(JsGeneratorCoreAutoconfigure.class) +@SpringBootApplication(scanBasePackageClasses = HelloViewController.class) +public class JsGeneratorDesktop extends Application { + private static ApplicationContext context; + private static FxmlResolver fxmlResolver; + private static Scene scene; + + public static void main(String[] args) { + context = SpringApplication.run(JsGeneratorDesktop.class, args); + fxmlResolver = context.getBean(FxmlResolver.class); + launch(JsGeneratorDesktop.class, args); + } + + /** + * Inject this bean to navigate from one view to another, like a router. + * + * @return + */ + @Bean + @Lazy + public FxmlNavigator fxmlNavigator() { + return scene::setRoot; + } + + @Bean + public FxmlResolver fxmlResolver() { + return path -> { + path = "com/osscameroon/jsgenerator/desktop/controller/%s.fxml".formatted(path); + final var loader = new FXMLLoader(new ClassPathResource(path).getURL()); + loader.setControllerFactory(context::getBean); + return (Parent) loader.load(); + }; + } + + @Override + public void start(Stage stage) throws IOException { + final var parent = fxmlResolver.resolve("hello-view"); + stage.setScene(scene = new Scene(parent)); + stage.show(); + } +} diff --git a/jsgenerator-desktop/src/main/java/com/osscameroon/jsgenerator/desktop/controller/FxmlNavigator.java b/jsgenerator-desktop/src/main/java/com/osscameroon/jsgenerator/desktop/controller/FxmlNavigator.java new file mode 100644 index 00000000..67d0487e --- /dev/null +++ b/jsgenerator-desktop/src/main/java/com/osscameroon/jsgenerator/desktop/controller/FxmlNavigator.java @@ -0,0 +1,8 @@ +package com.osscameroon.jsgenerator.desktop.controller; + +import javafx.scene.Parent; + +@FunctionalInterface +public interface FxmlNavigator { + void navigate(Parent parent); +} diff --git a/jsgenerator-desktop/src/main/java/com/osscameroon/jsgenerator/desktop/controller/FxmlResolver.java b/jsgenerator-desktop/src/main/java/com/osscameroon/jsgenerator/desktop/controller/FxmlResolver.java new file mode 100644 index 00000000..b74cf34e --- /dev/null +++ b/jsgenerator-desktop/src/main/java/com/osscameroon/jsgenerator/desktop/controller/FxmlResolver.java @@ -0,0 +1,10 @@ +package com.osscameroon.jsgenerator.desktop.controller; + +import javafx.scene.Parent; + +import java.io.IOException; + +@FunctionalInterface +public interface FxmlResolver { + Parent resolve(String relativePathWithoutExtension) throws IOException; +} diff --git a/jsgenerator-desktop/src/main/java/com/osscameroon/jsgenerator/desktop/controller/HelloViewController.java b/jsgenerator-desktop/src/main/java/com/osscameroon/jsgenerator/desktop/controller/HelloViewController.java new file mode 100644 index 00000000..aa18df1f --- /dev/null +++ b/jsgenerator-desktop/src/main/java/com/osscameroon/jsgenerator/desktop/controller/HelloViewController.java @@ -0,0 +1,34 @@ +package com.osscameroon.jsgenerator.desktop.controller; + +import com.osscameroon.jsgenerator.core.Converter; +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.control.TextArea; +import org.springframework.stereotype.Component; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +@Component +public final class HelloViewController { + private final Converter converter; + + @FXML + private TextArea inputArea; + @FXML + private Label outputLabel; + + public HelloViewController(Converter converter) { + this.converter = converter; + } + + @FXML + private void convert() throws IOException { + try (var stream = new ByteArrayOutputStream()) { + converter.convert(new ByteArrayInputStream(inputArea.textProperty().getValue().getBytes()), stream); + outputLabel.setText(stream.toString(StandardCharsets.UTF_8)); + } + } +} diff --git a/jsgenerator-desktop/src/main/java/module-info.java b/jsgenerator-desktop/src/main/java/module-info.java index 6eb03ff2..eeebdaca 100644 --- a/jsgenerator-desktop/src/main/java/module-info.java +++ b/jsgenerator-desktop/src/main/java/module-info.java @@ -1,18 +1,18 @@ module com.osscameroon.jsgenerator.desktop { + exports com.osscameroon.jsgenerator.desktop.autoconfigure; + exports com.osscameroon.jsgenerator.desktop.controller; + + opens com.osscameroon.jsgenerator.desktop.controller to javafx.fxml, spring.beans; + opens com.osscameroon.jsgenerator.desktop.autoconfigure to javafx.fxml, spring.beans; requires com.osscameroon.jsgenerator.core; - requires lombok; - requires javafx.controls; - requires javafx.fxml; - requires javafx.web; - requires org.controlsfx.controls; - requires com.dlsc.formsfx; - requires net.synedra.validatorfx; - requires org.kordamp.ikonli.javafx; - requires org.kordamp.bootstrapfx.core; - requires eu.hansolo.tilesfx; + requires spring.boot.autoconfigure; + requires spring.boot; + requires spring.context; - opens com.osscameroon.jsgenerator.desktop to javafx.fxml; - exports com.osscameroon.jsgenerator.desktop; -} \ No newline at end of file + requires javafx.graphics; + requires javafx.controls; + requires javafx.fxml; + requires spring.core; +} diff --git a/jsgenerator-desktop/src/main/resources/application.yml b/jsgenerator-desktop/src/main/resources/application.yml new file mode 100644 index 00000000..29ae4af4 --- /dev/null +++ b/jsgenerator-desktop/src/main/resources/application.yml @@ -0,0 +1,3 @@ +spring: + banner: + location: classpath:/banner.txt diff --git a/jsgenerator-desktop/src/main/resources/banner.txt b/jsgenerator-desktop/src/main/resources/banner.txt new file mode 100644 index 00000000..5c9612c8 --- /dev/null +++ b/jsgenerator-desktop/src/main/resources/banner.txt @@ -0,0 +1,9 @@ + + _ _____ _____ ______ _ _ ______ _____ _______ ____ _____ _____ ______ _____ _ _________ ____ _____ + | |/ ____|/ ____| ____| \ | | ____| __ \ /\|__ __/ __ \| __ \ | __ \| ____|/ ____| |/ /__ __/ __ \| __ \ + | | (___ | | __| |__ | \| | |__ | |__) | / \ | | | | | | |__) |_____| | | | |__ | (___ | ' / | | | | | | |__) | + _ | |\___ \| | |_ | __| | . ` | __| | _ / / /\ \ | | | | | | _ /______| | | | __| \___ \| < | | | | | | ___/ + | |__| |____) | |__| | |____| |\ | |____| | \ \ / ____ \| | | |__| | | \ \ | |__| | |____ ____) | . \ | | | |__| | | + \____/|_____/ \_____|______|_| \_|______|_| \_\/_/ \_\_| \____/|_| \_\ |_____/|______|_____/|_|\_\ |_| \____/|_| + + diff --git a/jsgenerator-desktop/src/main/resources/com/osscameroon/jsgenerator/desktop/controller/hello-view.fxml b/jsgenerator-desktop/src/main/resources/com/osscameroon/jsgenerator/desktop/controller/hello-view.fxml new file mode 100644 index 00000000..ce6799d1 --- /dev/null +++ b/jsgenerator-desktop/src/main/resources/com/osscameroon/jsgenerator/desktop/controller/hello-view.fxml @@ -0,0 +1,18 @@ + + + + + + + + + +