Anpassung an DQFL Specification V 1.1

This commit is contained in:
2026-04-05 15:21:15 +02:00
parent 4b770fecc3
commit 7cdb676dee
6 changed files with 201 additions and 54 deletions

View File

@@ -1,4 +1,3 @@
package de.dogfire.dqfl.model;
import java.util.ArrayList;
@@ -14,18 +13,20 @@ public final class DqflCategory
private final String alias;
private final String title;
private final String usePool;
private final String useCategory;
private final LayoutType layout;
private final GridSize size;
private final List<DqflPhase> phases;
private DqflCategory(final Builder builder)
{
this.alias = Objects.requireNonNull(builder.alias, "alias must not be null");
this.title = builder.title;
this.usePool = builder.usePool;
this.layout = builder.layout;
this.size = builder.size;
this.phases = Collections.unmodifiableList(new ArrayList<>(builder.phases));
this.alias = Objects.requireNonNull(builder.alias, "alias must not be null");
this.title = builder.title;
this.usePool = builder.usePool;
this.useCategory = builder.useCategory;
this.layout = builder.layout;
this.size = builder.size;
this.phases = Collections.unmodifiableList(new ArrayList<>(builder.phases));
}
public String getAlias()
@@ -44,6 +45,12 @@ public final class DqflCategory
return this.usePool;
}
/** Kann null sein — USE_CATEGORY ist optional (V1_1). */
public String getUseCategory()
{
return this.useCategory;
}
public LayoutType getLayout()
{
return this.layout;
@@ -66,6 +73,7 @@ public final class DqflCategory
return "CATEGORY " + this.alias
+ " [title=" + this.title
+ ", pool=" + this.usePool
+ ", category=" + this.useCategory
+ ", phases=" + this.phases.size() + "]";
}
@@ -83,6 +91,7 @@ public final class DqflCategory
private final String alias;
private String title;
private String usePool;
private String useCategory;
private LayoutType layout;
private GridSize size;
private final List<DqflPhase> phases = new ArrayList<>();
@@ -104,6 +113,12 @@ public final class DqflCategory
return this;
}
public Builder useCategory(final String useCategory)
{
this.useCategory = useCategory;
return this;
}
public Builder layout(final LayoutType layout)
{
this.layout = layout;
@@ -127,4 +142,4 @@ public final class DqflCategory
return new DqflCategory(this);
}
}
}
}

View File

@@ -10,7 +10,7 @@ import de.dogfire.dqfl.error.DqflParseException;
import de.dogfire.dqfl.model.*;
/**
* Parser für DQFL V1 Dokumente.
* Parser für DQFL V1/V1_1 Dokumente.
* Liest ein einrückungssensitives Textformat und erzeugt einen {@link DqflDocument} AST.
*/
public final class DqflParser
@@ -330,6 +330,10 @@ public final class DqflParser
catBuilder.usePool(child.value);
this.cursor++;
}
case "USE_CATEGORY" -> {
catBuilder.useCategory(this.unquote(child.value));
this.cursor++;
}
case "LAYOUT" -> {
final LayoutType lt = LayoutType.parse(child.value);
if(lt == null)
@@ -670,4 +674,4 @@ public final class DqflParser
+ this.keyword + (this.value != null ? " " + this.value : "");
}
}
}
}

View File

@@ -1,4 +1,3 @@
package de.dogfire.dqfl.validator;
import java.util.ArrayList;
@@ -12,8 +11,8 @@ import de.dogfire.dqfl.error.DqflValidationResult;
import de.dogfire.dqfl.model.*;
/**
* Validator für DQFL V1 Dokumente.
* Prüft alle Fachregeln aus Kapitel 10 der Spezifikation.
* Validator für DQFL V1/V1_1 Dokumente.
* Prüft alle Fachregeln aus der Spezifikation.
*/
public final class DqflValidator
{
@@ -40,25 +39,18 @@ public final class DqflValidator
errors.add(DqflError.error("FLOW is required"));
}
// 3. SOURCE-Aliase müssen eindeutig sein (bereits durch Map im Parser sichergestellt,
// aber wir prüfen trotzdem ob Sources vorhanden sind wenn Pools sie referenzieren)
// 4. POOL-Validierung
// 3. POOL-Validierung
this.validatePools(document, errors);
// 5. ROUND-Validierung
// 4. ROUND-Validierung
this.validateRounds(document, errors);
// 6. Alias-Eindeutigkeit über Objektarten
// 5. Alias-Eindeutigkeit über Objektarten
this.validateAliasUniqueness(document, errors);
return new DqflValidationResult(errors);
}
// ================================================================
// Pool-Validierung
// ================================================================
private void validatePools(final DqflDocument document, final List<DqflError> errors)
{
for(final DqflPool pool : document.getPools().values())
@@ -82,10 +74,6 @@ public final class DqflValidator
}
}
// ================================================================
// Round-Validierung
// ================================================================
private void validateRounds(final DqflDocument document, final List<DqflError> errors)
{
if(document.getRounds().isEmpty())
@@ -119,10 +107,6 @@ public final class DqflValidator
}
}
// ================================================================
// Category-Validierung
// ================================================================
private void validateCategory(
final DqflCategory category,
final DqflDocument document,
@@ -153,6 +137,26 @@ public final class DqflValidator
}
}
// USE_CATEGORY Validierung (V1_1)
if(category.getUseCategory() != null)
{
// USE_CATEGORY ohne USE_POOL ist ein Syntaxfehler
if(category.getUsePool() == null || category.getUsePool().isBlank())
{
errors.add(DqflError.error(
"CATEGORY '" + category.getAlias()
+ "' has USE_CATEGORY without USE_POOL"));
}
// Wert darf nicht leer sein
if(category.getUseCategory().isBlank())
{
errors.add(DqflError.error(
"CATEGORY '" + category.getAlias()
+ "' USE_CATEGORY must not be empty"));
}
}
// SIZE nur gültig wenn LAYOUT vorhanden
if(category.getSize() != null && category.getLayout() == null)
{
@@ -182,10 +186,6 @@ public final class DqflValidator
}
}
// ================================================================
// Phase-Validierung
// ================================================================
private void validatePhase(
final DqflPhase phase,
final String categoryAlias,
@@ -236,19 +236,10 @@ public final class DqflValidator
}
}
// ================================================================
// Alias-Eindeutigkeit (über Objektarten)
// ================================================================
private void validateAliasUniqueness(
final DqflDocument document,
final List<DqflError> errors)
{
// SOURCE-Aliase eindeutig (Map-Struktur prüft bereits implizit,
// aber bei Duplikaten im Dokument wurde der erste überschrieben)
// POOL-Aliase eindeutig (gleiche Map-Logik)
// Wir prüfen explizit ob Pool-Aliase und Source-Aliase kollidieren (optional, sauber)
final Set<String> sourceAliases = document.getSources().keySet();
final Set<String> poolAliases = document.getPools().keySet();
@@ -262,4 +253,4 @@ public final class DqflValidator
}
}
}
}
}