commit 7ad05e5b14e007960399c78a8aa7b23fa3889a01 Author: Guillaume Dugas Date: Thu Feb 19 09:58:13 2026 +0100 Init diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..abd47ed --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,43 @@ +name: Maven build +run-name: Build application with maven +on: [ push ] + +jobs: + build: + runs-on: ubuntu-latest + env: + MAVEN_ACCESS_TOKEN: ${{ secrets.CI_TOKEN }} + MAVEN_REPO_OWNER: ${{ gitea.actor }} + RELEASE_VERSION_BASE: 1.0 + steps: + - name: Check out latest repository code + uses: actions/checkout@v4 + + - uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Set versions + run: | + VERSION_BASE=$RELEASE_VERSION_BASE + if [ "$GITHUB_REF_TYPE" = "tag" ]; then + VERSION_BASE="${GITHUB_REF_NAME}" + elif echo "$GITHUB_REF_NAME" | grep -qE '^release/'; then + VERSION_BASE="${GITHUB_REF_NAME#release/}" + fi + if [ "$GITHUB_REF_TYPE" = "branch" ]; then + BUILD_VERSION="${VERSION_BASE}-SNAPSHOT" + else + BUILD_VERSION="${VERSION_BASE}" + fi + ./mvnw versions:set -DnewVersion=${BUILD_VERSION} -DprocessAllModules=true + + - name: Build project + run: ./mvnw -s .mvn/settings.xml clean install -DskipTests + + - name: Run tests + run: ./mvnw -s .mvn/settings.xml test + + - name: Deploy project + run: ./mvnw -s .mvn/settings.xml deploy diff --git a/bom/pom.xml b/bom/pom.xml new file mode 100644 index 0000000..5f9fe2a --- /dev/null +++ b/bom/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + + + fr.cnd.compositor + 1.0-SNAPSHOT + root + ../pom.xml + + + bom + Bom + pom + + + 3.14.1 + ${surefire-plugin.version} + 21 + UTF-8 + UTF-8 + quarkus-bom + io.quarkus.platform + 3.31.3 + ${quarkus.platform.version} + true + 3.5.4 + + + 1.18.42 + 4.1.0 + + + + + + io.pebbletemplates + pebble + ${pebble.version} + + + org.projectlombok + lombok + ${lombok.version} + provided + + + + + diff --git a/builder/pom.xml b/builder/pom.xml new file mode 100644 index 0000000..f449476 --- /dev/null +++ b/builder/pom.xml @@ -0,0 +1,76 @@ + + + 4.0.0 + + fr.cnd.compositor + bom + 1.0-SNAPSHOT + ../bom/pom.xml + + + pom + builder + Builder - Ext + + + + + io.quarkus + quarkus-bom + ${quarkus.version} + pom + import + + + + + + + + + io.quarkus + quarkus-maven-plugin + ${quarkus.version} + + + maven-surefire-plugin + ${surefire-plugin.version} + + + org.jboss.logmanager.LogManager + ${maven.home} + ${settings.localRepository} + + + + + maven-failsafe-plugin + ${failsafe-plugin.version} + + + org.jboss.logmanager.LogManager + ${maven.home} + ${settings.localRepository} + + + + + maven-compiler-plugin + ${compiler-plugin.version} + + + + org.projectlombok + lombok + ${lombok.version} + + + true + + + + + + diff --git a/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/models/BlockRenderDefinition.java b/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/models/BlockRenderDefinition.java new file mode 100644 index 0000000..8cd5265 --- /dev/null +++ b/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/models/BlockRenderDefinition.java @@ -0,0 +1,17 @@ +package fr.cnd.compositor.blocks.models; + +import lombok.*; + +import java.util.List; +import java.util.Map; + +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class BlockRenderDefinition { + String name; + Map inputs; + Map> slots; +} diff --git a/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/models/BlockRenderRequest.java b/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/models/BlockRenderRequest.java new file mode 100644 index 0000000..ed32c14 --- /dev/null +++ b/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/models/BlockRenderRequest.java @@ -0,0 +1,15 @@ +package fr.cnd.compositor.blocks.models; + +import lombok.*; + +import java.util.List; +import java.util.Map; + +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class BlockRenderRequest { + Map> definitions; +} diff --git a/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/models/BlockRenderResult.java b/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/models/BlockRenderResult.java new file mode 100644 index 0000000..085a1a7 --- /dev/null +++ b/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/models/BlockRenderResult.java @@ -0,0 +1,15 @@ +package fr.cnd.compositor.blocks.models; + +import lombok.*; + +import java.util.List; +import java.util.Map; + +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class BlockRenderResult { + Map> result; +} diff --git a/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/pebble/AbstractPebbleBlockTemplate.java b/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/pebble/AbstractPebbleBlockTemplate.java new file mode 100644 index 0000000..ea394b4 --- /dev/null +++ b/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/pebble/AbstractPebbleBlockTemplate.java @@ -0,0 +1,28 @@ +package fr.cnd.compositor.blocks.pebble; + +import fr.cnd.compositor.blocks.models.BlockRenderDefinition; +import fr.cnd.compositor.blocks.specs.BlockTemplate; +import io.smallrye.mutiny.Uni; +import jakarta.inject.Inject; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public abstract class AbstractPebbleBlockTemplate implements BlockTemplate { + @Inject + PebbleBlockEngine engine; + + public void setEngine(PebbleBlockEngine engine) { + this.engine = engine; + } + + public abstract Uni getTemplate(); + + @Override + public Uni render(BlockRenderDefinition definition) { + final Map context = new HashMap<>(Optional.ofNullable(definition.getInputs()).orElse(new HashMap<>())); + return getTemplate() + .chain(template -> engine.render(template, context)); + } +} diff --git a/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/pebble/PebbleBlocksExtension.java b/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/pebble/PebbleBlocksExtension.java new file mode 100644 index 0000000..a4cb1e5 --- /dev/null +++ b/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/pebble/PebbleBlocksExtension.java @@ -0,0 +1,19 @@ +package fr.cnd.compositor.blocks.pebble; + +import io.pebbletemplates.pebble.extension.AbstractExtension; +import io.pebbletemplates.pebble.extension.Function; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import java.util.Map; + +@ApplicationScoped +public class PebbleBlocksExtension extends AbstractExtension { + + @Inject + PebbleSlotFunction pebbleSlotFunction; + public Map getFunctions() { + return Map.of("slot", pebbleSlotFunction); + } + +} diff --git a/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/pebble/PebbleSlotFunction.java b/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/pebble/PebbleSlotFunction.java new file mode 100644 index 0000000..da39d5a --- /dev/null +++ b/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/pebble/PebbleSlotFunction.java @@ -0,0 +1,33 @@ +package fr.cnd.compositor.blocks.pebble; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.pebbletemplates.pebble.extension.Function; +import io.pebbletemplates.pebble.extension.escaper.SafeString; +import io.pebbletemplates.pebble.template.EvaluationContext; +import io.pebbletemplates.pebble.template.PebbleTemplate; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import java.util.List; +import java.util.Map; + +@ApplicationScoped +public class PebbleSlotFunction implements Function { + + @Inject + ObjectMapper objectMapper; + + @Override + public SafeString execute(Map args, PebbleTemplate self, EvaluationContext context, int lineNumber) { + final Object slotsVar = context.getVariable("__slots__"); + final Map slots = objectMapper.convertValue(slotsVar, new TypeReference<>() {}); + final String slotName = (String) args.get("name"); + return slots != null && slots.containsKey(slotName) ? new SafeString(slots.get(slotName)) : new SafeString(""); + } + + @Override + public List getArgumentNames() { + return List.of("name"); + } +} diff --git a/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/specs/BlockConfiguration.java b/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/specs/BlockConfiguration.java new file mode 100644 index 0000000..4bd2823 --- /dev/null +++ b/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/specs/BlockConfiguration.java @@ -0,0 +1,10 @@ +package fr.cnd.compositor.blocks.specs; + +import io.smallrye.mutiny.Uni; + +import java.util.Map; + +public interface BlockConfiguration { + Uni getBlockTemplateName(); + Uni> mapInputs(Map inputs); +} diff --git a/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/specs/ContextMapping.java b/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/specs/ContextMapping.java new file mode 100644 index 0000000..6a29dba --- /dev/null +++ b/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/specs/ContextMapping.java @@ -0,0 +1,19 @@ +package fr.cnd.compositor.blocks.specs; + +import io.smallrye.mutiny.Uni; + +import java.util.Map; + +/** + * Maps user-provided inputs to the final template context. + */ +public interface ContextMapping { + + /** + * Transforms the given user inputs into the context that will be passed to the template engine. + * + * @param inputs the raw user-provided input entries + * @return a {@link Uni} emitting the resulting template context + */ + Uni> map(Map inputs); +} diff --git a/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/specs/ContextMappingResolver.java b/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/specs/ContextMappingResolver.java new file mode 100644 index 0000000..b110f49 --- /dev/null +++ b/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/specs/ContextMappingResolver.java @@ -0,0 +1,8 @@ +package fr.cnd.compositor.blocks.specs; + +import io.smallrye.mutiny.Uni; + +public interface ContextMappingResolver { + Uni resolveContextMapping(String contextMappingIdentifier); +} + diff --git a/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/templates/HtmlBlockTemplate.java b/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/templates/HtmlBlockTemplate.java new file mode 100644 index 0000000..f499321 --- /dev/null +++ b/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/templates/HtmlBlockTemplate.java @@ -0,0 +1,24 @@ +package fr.cnd.compositor.blocks.templates; + +import fr.cnd.compositor.blocks.pebble.AbstractPebbleBlockTemplate; +import io.smallrye.common.annotation.Identifier; +import io.smallrye.mutiny.Uni; +import jakarta.enterprise.context.ApplicationScoped; + +@Identifier("html") +@ApplicationScoped +public class HtmlBlockTemplate extends AbstractPebbleBlockTemplate { + @Override + public Uni getTemplate() { + return Uni.createFrom().item(""" + + + {{title}} + + + {{content}} + + + """); + } +} diff --git a/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/templates/HtmlProductConfiguration.java b/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/templates/HtmlProductConfiguration.java new file mode 100644 index 0000000..ddd43b7 --- /dev/null +++ b/modules/core/runtime/src/main/java/fr/cnd/compositor/blocks/templates/HtmlProductConfiguration.java @@ -0,0 +1,35 @@ +package fr.cnd.compositor.blocks.templates; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import fr.cnd.compositor.blocks.specs.BlockConfiguration; +import io.smallrye.common.annotation.Identifier; +import io.smallrye.mutiny.Uni; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import java.util.HashMap; +import java.util.Map; + +@Identifier("product") +@ApplicationScoped +public class HtmlProductConfiguration implements BlockConfiguration { + + @Inject + ObjectMapper objectMapper; + + @Override + public Uni getBlockTemplateName() { + return Uni.createFrom().item("html"); + } + + @Override + public Uni> mapInputs(Map inputs) { + Map product = objectMapper.convertValue(inputs.getOrDefault("product", new HashMap<>()), new TypeReference<>() {}); + + return Uni.createFrom().item(Map.of( + "title", product.getOrDefault("title", ""), + "content", product.getOrDefault("name", "") + )); + } +} diff --git a/modules/core/runtime/src/main/resources/META-INF/beans.xml b/modules/core/runtime/src/main/resources/META-INF/beans.xml new file mode 100644 index 0000000..e69de29 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..cf23d7e --- /dev/null +++ b/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + fr.cnd.compositor + root + 1.0-SNAPSHOT + + Blocks + pom + + + bom + builder + + modules/core + + +