[patchwork, core, extensions] Hugely simplify Patchworks
This commit is contained in:
@@ -5,8 +5,20 @@ import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.comment.impl.CommentExtensionImpl;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public interface CommentExtension extends TweedExtension {
|
||||
Class<? extends CommentExtension> DEFAULT = CommentExtensionImpl.class;
|
||||
|
||||
static <C extends ConfigEntry<?>> Consumer<C> baseComment(String baseComment) {
|
||||
return entry -> {
|
||||
CommentExtension extension = entry.container().extension(CommentExtension.class)
|
||||
.orElseThrow(() -> new IllegalStateException("No comment extension registered"));
|
||||
extension.setBaseComment(entry, baseComment);
|
||||
};
|
||||
}
|
||||
|
||||
void setBaseComment(ConfigEntry<?> configEntry, String baseComment);
|
||||
|
||||
@Nullable String getFullComment(ConfigEntry<?> configEntry);
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
package de.siphalor.tweed5.defaultextensions.comment.api;
|
||||
|
||||
public interface EntryComment {
|
||||
String comment();
|
||||
}
|
||||
@@ -2,32 +2,32 @@ package de.siphalor.tweed5.defaultextensions.comment.impl;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
||||
import de.siphalor.tweed5.core.api.container.ConfigContainerSetupPhase;
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.extension.EntryExtensionsData;
|
||||
import de.siphalor.tweed5.core.api.extension.RegisteredExtensionData;
|
||||
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
||||
import de.siphalor.tweed5.core.api.extension.TweedExtensionSetupContext;
|
||||
import de.siphalor.tweed5.core.api.middleware.DefaultMiddlewareContainer;
|
||||
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
||||
import de.siphalor.tweed5.data.extension.api.TweedEntryWriter;
|
||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteRelatedExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.comment.api.*;
|
||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentModifyingExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentProducer;
|
||||
import de.siphalor.tweed5.patchwork.api.PatchworkPartAccess;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Value;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@AutoService(CommentExtension.class)
|
||||
public class CommentExtensionImpl implements ReadWriteRelatedExtension, CommentExtension {
|
||||
private final ConfigContainer<?> configContainer;
|
||||
@Getter
|
||||
private final RegisteredExtensionData<EntryExtensionsData, InternalCommentEntryData> internalEntryDataExtension;
|
||||
private final PatchworkPartAccess<CustomEntryData> customEntryDataAccess;
|
||||
private final DefaultMiddlewareContainer<CommentProducer> middlewareContainer;
|
||||
|
||||
public CommentExtensionImpl(ConfigContainer<?> configContainer, TweedExtensionSetupContext context) {
|
||||
this.configContainer = configContainer;
|
||||
this.internalEntryDataExtension = context.registerEntryExtensionData(InternalCommentEntryData.class);
|
||||
context.registerEntryExtensionData(EntryComment.class);
|
||||
this.customEntryDataAccess = context.registerEntryExtensionData(CustomEntryData.class);
|
||||
this.middlewareContainer = new DefaultMiddlewareContainer<>();
|
||||
}
|
||||
|
||||
@@ -48,31 +48,49 @@ public class CommentExtensionImpl implements ReadWriteRelatedExtension, CommentE
|
||||
|
||||
@Override
|
||||
public @Nullable Middleware<TweedEntryWriter<?, ?>> entryWriterMiddleware() {
|
||||
return TweedEntryWriterCommentMiddleware.INSTANCE;
|
||||
return new TweedEntryWriterCommentMiddleware(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBaseComment(ConfigEntry<?> configEntry, String baseComment) {
|
||||
if (configEntry.container() != configContainer) {
|
||||
throw new IllegalArgumentException("config entry doesn't belong to config container of this extension");
|
||||
} else if (configContainer.setupPhase().compareTo(ConfigContainerSetupPhase.INITIALIZED) >= 0) {
|
||||
throw new IllegalStateException("config container must not be initialized");
|
||||
}
|
||||
|
||||
getOrCreateCustomEntryData(configEntry).baseComment(baseComment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initEntry(ConfigEntry<?> configEntry) {
|
||||
EntryExtensionsData entryExtensionsData = configEntry.extensionsData();
|
||||
String baseComment;
|
||||
if (entryExtensionsData.isPatchworkPartSet(EntryComment.class)) {
|
||||
baseComment = ((EntryComment) entryExtensionsData).comment();
|
||||
} else {
|
||||
baseComment = "";
|
||||
}
|
||||
CustomEntryData entryData = getOrCreateCustomEntryData(configEntry);
|
||||
entryData.commentProducer(middlewareContainer.process(entry -> entryData.baseComment()));
|
||||
}
|
||||
|
||||
CommentProducer middleware = middlewareContainer.process(entry -> baseComment);
|
||||
internalEntryDataExtension.set(entryExtensionsData, new InternalCommentEntryDataImpl(middleware));
|
||||
private CustomEntryData getOrCreateCustomEntryData(ConfigEntry<?> entry) {
|
||||
CustomEntryData customEntryData = entry.extensionsData().get(customEntryDataAccess);
|
||||
if (customEntryData == null) {
|
||||
customEntryData = new CustomEntryData();
|
||||
entry.extensionsData().set(customEntryDataAccess, customEntryData);
|
||||
}
|
||||
return customEntryData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getFullComment(@NonNull ConfigEntry<?> configEntry) {
|
||||
String comment = ((InternalCommentEntryData) configEntry.extensionsData()).commentProducer().createComment(configEntry);
|
||||
public @Nullable String getFullComment(ConfigEntry<?> configEntry) {
|
||||
CustomEntryData customEntryData = configEntry.extensionsData().get(customEntryDataAccess);
|
||||
if (customEntryData == null) {
|
||||
return null;
|
||||
}
|
||||
String comment = customEntryData.commentProducer().createComment(configEntry);
|
||||
return comment.isEmpty() ? null : comment;
|
||||
}
|
||||
|
||||
@Value
|
||||
private static class InternalCommentEntryDataImpl implements InternalCommentEntryData {
|
||||
CommentProducer commentProducer;
|
||||
|
||||
@Data
|
||||
private static class CustomEntryData {
|
||||
private String baseComment = "";
|
||||
private CommentProducer commentProducer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
package de.siphalor.tweed5.defaultextensions.comment.impl;
|
||||
|
||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentProducer;
|
||||
|
||||
public interface InternalCommentEntryData {
|
||||
CommentProducer commentProducer();
|
||||
}
|
||||
@@ -5,12 +5,14 @@ import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
||||
import de.siphalor.tweed5.data.extension.api.TweedEntryWriter;
|
||||
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
|
||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
class TweedEntryWriterCommentMiddleware implements Middleware<TweedEntryWriter<?, ?>> {
|
||||
public static final TweedEntryWriterCommentMiddleware INSTANCE = new TweedEntryWriterCommentMiddleware();
|
||||
private final CommentExtension commentExtension;
|
||||
|
||||
@Override
|
||||
public String id() {
|
||||
@@ -49,7 +51,7 @@ class TweedEntryWriterCommentMiddleware implements Middleware<TweedEntryWriter<?
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
private static class CompoundDataVisitor implements TweedDataVisitor {
|
||||
private class CompoundDataVisitor implements TweedDataVisitor {
|
||||
private final TweedDataVisitor delegate;
|
||||
private final CompoundConfigEntry<?> compoundConfigEntry;
|
||||
|
||||
@@ -134,11 +136,7 @@ class TweedEntryWriterCommentMiddleware implements Middleware<TweedEntryWriter<?
|
||||
}
|
||||
}
|
||||
|
||||
private static @Nullable String getEntryComment(ConfigEntry<?> entry) {
|
||||
if (!entry.extensionsData().isPatchworkPartSet(InternalCommentEntryData.class)) {
|
||||
return null;
|
||||
}
|
||||
String comment = ((InternalCommentEntryData) entry.extensionsData()).commentProducer().createComment(entry).trim();
|
||||
return comment.isEmpty() ? null : comment;
|
||||
private @Nullable String getEntryComment(ConfigEntry<?> entry) {
|
||||
return commentExtension.getFullComment(entry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import org.jspecify.annotations.Nullable;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
|
||||
public class PathTracking implements PatherData {
|
||||
public class PathTracking {
|
||||
private final StringBuilder pathBuilder = new StringBuilder(256);
|
||||
private final Deque<Context> contextStack = new ArrayDeque<>(50);
|
||||
private final Deque<String> pathParts = new ArrayDeque<>(50);
|
||||
@@ -52,8 +52,7 @@ public class PathTracking implements PatherData {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String valuePath() {
|
||||
public String currentPath() {
|
||||
return pathBuilder.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package de.siphalor.tweed5.defaultextensions.pather.api;
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class PathTrackingConfigEntryValueVisitor implements ConfigEntryValueVisitor {
|
||||
@@ -10,7 +11,7 @@ public class PathTrackingConfigEntryValueVisitor implements ConfigEntryValueVisi
|
||||
private final PathTracking pathTracking;
|
||||
|
||||
@Override
|
||||
public <T> void visitEntry(ConfigEntry<T> entry, T value) {
|
||||
public <T extends @Nullable Object> void visitEntry(ConfigEntry<T> entry, T value) {
|
||||
delegate.visitEntry(entry, value);
|
||||
entryVisited();
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
package de.siphalor.tweed5.defaultextensions.pather.api;
|
||||
|
||||
/**
|
||||
* Extension data for {@link de.siphalor.tweed5.data.extension.api.extension.ReadWriteContextExtensionsData}
|
||||
* that provides the path to the value currently being read/written.
|
||||
*/
|
||||
public interface PatherData {
|
||||
String valuePath();
|
||||
}
|
||||
@@ -1,8 +1,13 @@
|
||||
package de.siphalor.tweed5.defaultextensions.pather.api;
|
||||
|
||||
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
||||
import de.siphalor.tweed5.data.extension.api.TweedReadContext;
|
||||
import de.siphalor.tweed5.data.extension.api.TweedWriteContext;
|
||||
import de.siphalor.tweed5.defaultextensions.pather.impl.PatherExtensionImpl;
|
||||
|
||||
public interface PatherExtension extends TweedExtension {
|
||||
Class<? extends PatherExtension> DEFAULT = PatherExtensionImpl.class;
|
||||
|
||||
String getPath(TweedReadContext context);
|
||||
String getPath(TweedWriteContext context);
|
||||
}
|
||||
|
||||
@@ -2,29 +2,33 @@ package de.siphalor.tweed5.defaultextensions.pather.impl;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.extension.RegisteredExtensionData;
|
||||
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
||||
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
||||
import de.siphalor.tweed5.data.extension.api.*;
|
||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteContextExtensionsData;
|
||||
import de.siphalor.tweed5.data.extension.api.TweedEntryReader;
|
||||
import de.siphalor.tweed5.data.extension.api.TweedEntryWriter;
|
||||
import de.siphalor.tweed5.data.extension.api.TweedReadContext;
|
||||
import de.siphalor.tweed5.data.extension.api.TweedWriteContext;
|
||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteExtensionSetupContext;
|
||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteRelatedExtension;
|
||||
import de.siphalor.tweed5.dataapi.api.TweedDataReader;
|
||||
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
|
||||
import de.siphalor.tweed5.defaultextensions.pather.api.*;
|
||||
import de.siphalor.tweed5.defaultextensions.pather.api.PathTracking;
|
||||
import de.siphalor.tweed5.defaultextensions.pather.api.PathTrackingDataReader;
|
||||
import de.siphalor.tweed5.defaultextensions.pather.api.PathTrackingDataVisitor;
|
||||
import de.siphalor.tweed5.defaultextensions.pather.api.PatherExtension;
|
||||
import de.siphalor.tweed5.patchwork.api.PatchworkPartAccess;
|
||||
import lombok.val;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.jspecify.annotations.NullUnmarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@AutoService(PatherExtension.class)
|
||||
@NullUnmarked
|
||||
public class PatherExtensionImpl implements PatherExtension, TweedExtension, ReadWriteRelatedExtension {
|
||||
private static final String PATHER_ID = "pather";
|
||||
|
||||
private RegisteredExtensionData<ReadWriteContextExtensionsData, PatherData> rwContextPathTrackingData;
|
||||
private Middleware<TweedEntryReader<?, ?>> entryReaderMiddleware;
|
||||
private Middleware<TweedEntryWriter<?, ?>> entryWriterMiddleware;
|
||||
private final Middleware<TweedEntryReader<?, ?>> entryReaderMiddleware = createEntryReaderMiddleware();
|
||||
private final Middleware<TweedEntryWriter<?, ?>> entryWriterMiddleware = createEntryWriterMiddleware();
|
||||
|
||||
private @Nullable PatchworkPartAccess<PathTracking> rwContextPathTrackingAccess;
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
@@ -33,13 +37,32 @@ public class PatherExtensionImpl implements PatherExtension, TweedExtension, Rea
|
||||
|
||||
@Override
|
||||
public void setupReadWriteExtension(ReadWriteExtensionSetupContext context) {
|
||||
rwContextPathTrackingData = context.registerReadWriteContextExtensionData(PatherData.class);
|
||||
|
||||
entryReaderMiddleware = createEntryReaderMiddleware();
|
||||
entryWriterMiddleware = createEntryWriterMiddleware();
|
||||
rwContextPathTrackingAccess = context.registerReadWriteContextExtensionData(PathTracking.class);
|
||||
}
|
||||
|
||||
private @NonNull Middleware<TweedEntryReader<?, ?>> createEntryReaderMiddleware() {
|
||||
@Override
|
||||
public String getPath(TweedReadContext context) {
|
||||
assert rwContextPathTrackingAccess != null;
|
||||
|
||||
PathTracking pathTracking = context.extensionsData().get(rwContextPathTrackingAccess);
|
||||
if (pathTracking == null) {
|
||||
throw new IllegalStateException("Path tracking is not active!");
|
||||
}
|
||||
return pathTracking.currentPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath(TweedWriteContext context) {
|
||||
assert rwContextPathTrackingAccess != null;
|
||||
|
||||
PathTracking pathTracking = context.extensionsData().get(rwContextPathTrackingAccess);
|
||||
if (pathTracking == null) {
|
||||
throw new IllegalStateException("Path tracking is not active!");
|
||||
}
|
||||
return pathTracking.currentPath();
|
||||
}
|
||||
|
||||
private Middleware<TweedEntryReader<?, ?>> createEntryReaderMiddleware() {
|
||||
return new Middleware<TweedEntryReader<?, ?>>() {
|
||||
@Override
|
||||
public String id() {
|
||||
@@ -48,16 +71,19 @@ public class PatherExtensionImpl implements PatherExtension, TweedExtension, Rea
|
||||
|
||||
@Override
|
||||
public TweedEntryReader<?, ?> process(TweedEntryReader<?, ?> inner) {
|
||||
assert rwContextPathTrackingAccess != null;
|
||||
|
||||
//noinspection unchecked
|
||||
val castedInner = (TweedEntryReader<Object, @NonNull ConfigEntry<Object>>) inner;
|
||||
|
||||
return (TweedDataReader reader, ConfigEntry<Object> entry, TweedReadContext context) -> {
|
||||
if (context.extensionsData().isPatchworkPartSet(PatherData.class)) {
|
||||
PathTracking pathTracking = context.extensionsData().get(rwContextPathTrackingAccess);
|
||||
if (pathTracking != null) {
|
||||
return castedInner.read(reader, entry, context);
|
||||
}
|
||||
|
||||
PathTracking pathTracking = new PathTracking();
|
||||
rwContextPathTrackingData.set(context.extensionsData(), pathTracking);
|
||||
pathTracking = new PathTracking();
|
||||
context.extensionsData().set(rwContextPathTrackingAccess, pathTracking);
|
||||
return castedInner.read(new PathTrackingDataReader(reader, pathTracking), entry, context);
|
||||
};
|
||||
}
|
||||
@@ -73,17 +99,20 @@ public class PatherExtensionImpl implements PatherExtension, TweedExtension, Rea
|
||||
|
||||
@Override
|
||||
public TweedEntryWriter<?, ?> process(TweedEntryWriter<?, ?> inner) {
|
||||
assert rwContextPathTrackingAccess != null;
|
||||
|
||||
//noinspection unchecked
|
||||
val castedInner = (TweedEntryWriter<Object, @NonNull ConfigEntry<Object>>) inner;
|
||||
|
||||
return (TweedDataVisitor writer, Object value, ConfigEntry<Object> entry, TweedWriteContext context) -> {
|
||||
if (context.extensionsData().isPatchworkPartSet(PatherData.class)) {
|
||||
PathTracking pathTracking = context.extensionsData().get(rwContextPathTrackingAccess);
|
||||
if (pathTracking != null) {
|
||||
castedInner.write(writer, value, entry, context);
|
||||
return;
|
||||
}
|
||||
|
||||
PathTracking pathTracking = new PathTracking();
|
||||
rwContextPathTrackingData.set(context.extensionsData(), pathTracking);
|
||||
pathTracking = new PathTracking();
|
||||
context.extensionsData().set(rwContextPathTrackingAccess, pathTracking);
|
||||
castedInner.write(new PathTrackingDataVisitor(writer, pathTracking), value, entry, context);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
package de.siphalor.tweed5.defaultextensions.validation.api;
|
||||
|
||||
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface EntrySpecificValidation {
|
||||
Collection<Middleware<ConfigEntryValidator>> validators();
|
||||
}
|
||||
@@ -2,12 +2,54 @@ package de.siphalor.tweed5.defaultextensions.validation.api;
|
||||
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
||||
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssue;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssues;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.validators.SimpleValidatorMiddleware;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.impl.ValidationExtensionImpl;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public interface ValidationExtension extends TweedExtension {
|
||||
Class<? extends ValidationExtension> DEFAULT = ValidationExtensionImpl.class;
|
||||
|
||||
static <C extends ConfigEntry<T>, T> Consumer<C> validators(ConfigEntryValidator... validators) {
|
||||
return entry -> {
|
||||
ValidationExtension extension = entry.container().extension(ValidationExtension.class)
|
||||
.orElseThrow(() -> new IllegalStateException("No validation extension registered"));
|
||||
extension.addValidators(entry, validators);
|
||||
};
|
||||
}
|
||||
|
||||
static <C extends ConfigEntry<T>, T> Function<C, ValidationIssues> validate(T value) {
|
||||
return entry -> {
|
||||
ValidationExtension extension = entry.container().extension(ValidationExtension.class)
|
||||
.orElseThrow(() -> new IllegalStateException("No validation extension registered"));
|
||||
return extension.validate(entry, value);
|
||||
};
|
||||
}
|
||||
|
||||
default <T> void addValidators(ConfigEntry<T> entry, ConfigEntryValidator... validators) {
|
||||
String lastId = null;
|
||||
for (ConfigEntryValidator validator : validators) {
|
||||
String id = UUID.randomUUID().toString();
|
||||
Set<String> mustComeAfter = lastId == null ? Collections.emptySet() : Collections.singleton(lastId);
|
||||
|
||||
addValidatorMiddleware(entry, new SimpleValidatorMiddleware(id, validator) {
|
||||
@Override
|
||||
public Set<String> mustComeAfter() {
|
||||
return mustComeAfter;
|
||||
}
|
||||
});
|
||||
|
||||
lastId = id;
|
||||
}
|
||||
}
|
||||
<T> void addValidatorMiddleware(ConfigEntry<T> entry, Middleware<ConfigEntryValidator> validator);
|
||||
|
||||
<T extends @Nullable Object> ValidationIssues validate(ConfigEntry<T> entry, T value);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package de.siphalor.tweed5.defaultextensions.validation.api.result;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -11,16 +12,16 @@ import java.util.function.Function;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class ValidationResult<T> {
|
||||
public class ValidationResult<T extends @Nullable Object> {
|
||||
private final T value;
|
||||
private final Collection<ValidationIssue> issues;
|
||||
private final boolean hasError;
|
||||
|
||||
public static <T> ValidationResult<T> ok(T value) {
|
||||
public static <T extends @Nullable Object> ValidationResult<T> ok(T value) {
|
||||
return new ValidationResult<>(value, Collections.emptyList(), false);
|
||||
}
|
||||
|
||||
public static <T> ValidationResult<T> withIssues(T value, Collection<ValidationIssue> issues) {
|
||||
public static <T extends @Nullable Object> ValidationResult<T> withIssues(T value, Collection<ValidationIssue> issues) {
|
||||
return new ValidationResult<>(value, issues, issuesContainError(issues));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
package de.siphalor.tweed5.defaultextensions.validation.impl;
|
||||
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.ConfigEntryValidator;
|
||||
|
||||
public interface InternalValidationEntryData {
|
||||
ConfigEntryValidator completeEntryValidator();
|
||||
}
|
||||
@@ -4,8 +4,6 @@ import com.google.auto.service.AutoService;
|
||||
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor;
|
||||
import de.siphalor.tweed5.core.api.extension.EntryExtensionsData;
|
||||
import de.siphalor.tweed5.core.api.extension.RegisteredExtensionData;
|
||||
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
||||
import de.siphalor.tweed5.core.api.extension.TweedExtensionSetupContext;
|
||||
import de.siphalor.tweed5.core.api.middleware.DefaultMiddlewareContainer;
|
||||
@@ -14,7 +12,6 @@ import de.siphalor.tweed5.core.api.middleware.MiddlewareContainer;
|
||||
import de.siphalor.tweed5.data.extension.api.TweedEntryReadException;
|
||||
import de.siphalor.tweed5.data.extension.api.TweedEntryReader;
|
||||
import de.siphalor.tweed5.data.extension.api.TweedReadContext;
|
||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteContextExtensionsData;
|
||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteExtensionSetupContext;
|
||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteRelatedExtension;
|
||||
import de.siphalor.tweed5.dataapi.api.TweedDataReader;
|
||||
@@ -22,20 +19,16 @@ import de.siphalor.tweed5.defaultextensions.comment.api.CommentModifyingExtensio
|
||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentProducer;
|
||||
import de.siphalor.tweed5.defaultextensions.pather.api.PathTracking;
|
||||
import de.siphalor.tweed5.defaultextensions.pather.api.PathTrackingConfigEntryValueVisitor;
|
||||
import de.siphalor.tweed5.defaultextensions.pather.api.PatherData;
|
||||
import de.siphalor.tweed5.defaultextensions.pather.api.PatherExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.ConfigEntryValidator;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.EntrySpecificValidation;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationProvidingExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssue;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssueLevel;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssues;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Value;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import de.siphalor.tweed5.patchwork.api.PatchworkPartAccess;
|
||||
import lombok.*;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
@@ -48,7 +41,7 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
||||
);
|
||||
private static final ConfigEntryValidator PRIMITIVE_VALIDATOR = new ConfigEntryValidator() {
|
||||
@Override
|
||||
public <T> ValidationResult<T> validate(@NotNull ConfigEntry<T> configEntry, @Nullable T value) {
|
||||
public <T> ValidationResult<T> validate(ConfigEntry<T> configEntry, @Nullable T value) {
|
||||
if (value == null) {
|
||||
//noinspection unchecked
|
||||
return (ValidationResult<T>) PRIMITIVE_IS_NULL_RESULT;
|
||||
@@ -57,33 +50,32 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> String description(@NotNull ConfigEntry<T> configEntry) {
|
||||
public <T> String description(ConfigEntry<T> configEntry) {
|
||||
return "Value must not be null.";
|
||||
}
|
||||
};
|
||||
private static final ConfigEntryValidator NOOP_VALIDATOR = new ConfigEntryValidator() {
|
||||
@Override
|
||||
public <T> ValidationResult<T> validate(@NotNull ConfigEntry<T> configEntry, @Nullable T value) {
|
||||
public <T> ValidationResult<@Nullable T> validate(ConfigEntry<T> configEntry, @Nullable T value) {
|
||||
return ValidationResult.ok(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> String description(@NotNull ConfigEntry<T> configEntry) {
|
||||
public <T> String description(ConfigEntry<T> configEntry) {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
private final ConfigContainer<?> configContainer;
|
||||
private final RegisteredExtensionData<EntryExtensionsData, InternalValidationEntryData> validationEntryDataExtension;
|
||||
private final PatchworkPartAccess<CustomEntryData> customEntryDataAccess;
|
||||
private final MiddlewareContainer<ConfigEntryValidator> entryValidatorMiddlewareContainer
|
||||
= new DefaultMiddlewareContainer<>();
|
||||
private @Nullable RegisteredExtensionData<ReadWriteContextExtensionsData, ValidationIssues>
|
||||
readContextValidationIssuesExtensionData;
|
||||
private @Nullable PatchworkPartAccess<ValidationIssues> readContextValidationIssuesAccess;
|
||||
private @Nullable PatherExtension patherExtension;
|
||||
|
||||
public ValidationExtensionImpl(ConfigContainer<?> configContainer, TweedExtensionSetupContext context) {
|
||||
this.configContainer = configContainer;
|
||||
this.validationEntryDataExtension = context.registerEntryExtensionData(InternalValidationEntryData.class);
|
||||
context.registerEntryExtensionData(EntrySpecificValidation.class);
|
||||
this.customEntryDataAccess = context.registerEntryExtensionData(CustomEntryData.class);
|
||||
context.registerExtension(PatherExtension.class);
|
||||
}
|
||||
|
||||
@@ -102,6 +94,9 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
||||
}
|
||||
}
|
||||
entryValidatorMiddlewareContainer.seal();
|
||||
|
||||
patherExtension = configContainer.extension(PatherExtension.class)
|
||||
.orElseThrow(() -> new IllegalStateException("Missing requested PatherExtension"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -116,16 +111,21 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
||||
public CommentProducer process(CommentProducer inner) {
|
||||
return entry -> {
|
||||
String baseComment = inner.createComment(entry);
|
||||
if (entry.extensionsData().isPatchworkPartSet(InternalValidationEntryData.class)) {
|
||||
String validationDescription = ((InternalValidationEntryData) entry.extensionsData())
|
||||
.completeEntryValidator()
|
||||
.description(entry)
|
||||
.trim();
|
||||
if (!validationDescription.isEmpty()) {
|
||||
baseComment += "\n\n" + validationDescription;
|
||||
}
|
||||
CustomEntryData entryData = entry.extensionsData().get(customEntryDataAccess);
|
||||
if (entryData == null || entryData.completeValidator() == null) {
|
||||
return baseComment;
|
||||
}
|
||||
String validationDescription = entryData.completeValidator()
|
||||
.description(entry)
|
||||
.trim();
|
||||
if (validationDescription.isEmpty()) {
|
||||
return baseComment;
|
||||
}
|
||||
if (baseComment.isEmpty()) {
|
||||
return validationDescription;
|
||||
} else {
|
||||
return "\n\n" + validationDescription;
|
||||
}
|
||||
return baseComment;
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -133,7 +133,13 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
||||
|
||||
@Override
|
||||
public void setupReadWriteExtension(ReadWriteExtensionSetupContext context) {
|
||||
readContextValidationIssuesExtensionData = context.registerReadWriteContextExtensionData(ValidationIssues.class);
|
||||
readContextValidationIssuesAccess = context.registerReadWriteContextExtensionData(ValidationIssues.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void addValidatorMiddleware(ConfigEntry<T> entry, Middleware<ConfigEntryValidator> validator) {
|
||||
CustomEntryData entryData = getOrCreateCustomEntryData(entry);
|
||||
entryData.addValidator(validator);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -145,26 +151,26 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
||||
baseValidator = NOOP_VALIDATOR;
|
||||
}
|
||||
|
||||
ConfigEntryValidator entryValidator;
|
||||
Collection<Middleware<ConfigEntryValidator>> entrySpecificValidators = getEntrySpecificValidators(configEntry);
|
||||
if (entrySpecificValidators.isEmpty()) {
|
||||
entryValidator = entryValidatorMiddlewareContainer.process(baseValidator);
|
||||
CustomEntryData entryData = getOrCreateCustomEntryData(configEntry);
|
||||
|
||||
if (entryData.validators().isEmpty()) {
|
||||
entryData.completeValidator(entryValidatorMiddlewareContainer.process(baseValidator));
|
||||
} else {
|
||||
DefaultMiddlewareContainer<ConfigEntryValidator> entrySpecificValidatorContainer = new DefaultMiddlewareContainer<>();
|
||||
entrySpecificValidatorContainer.registerAll(entryValidatorMiddlewareContainer.middlewares());
|
||||
entrySpecificValidatorContainer.registerAll(entrySpecificValidators);
|
||||
entrySpecificValidatorContainer.registerAll(entryData.validators());
|
||||
entrySpecificValidatorContainer.seal();
|
||||
entryValidator = entrySpecificValidatorContainer.process(baseValidator);
|
||||
entryData.completeValidator(entrySpecificValidatorContainer.process(baseValidator));
|
||||
}
|
||||
|
||||
validationEntryDataExtension.set(configEntry.extensionsData(), new InternalValidationEntryDataImpl(entryValidator));
|
||||
}
|
||||
|
||||
private Collection<Middleware<ConfigEntryValidator>> getEntrySpecificValidators(ConfigEntry<?> configEntry) {
|
||||
if (!configEntry.extensionsData().isPatchworkPartSet(EntrySpecificValidation.class)) {
|
||||
return Collections.emptyList();
|
||||
private CustomEntryData getOrCreateCustomEntryData(ConfigEntry<?> entry) {
|
||||
CustomEntryData entryData = entry.extensionsData().get(customEntryDataAccess);
|
||||
if (entryData == null) {
|
||||
entryData = new CustomEntryData();
|
||||
entry.extensionsData().set(customEntryDataAccess, entryData);
|
||||
}
|
||||
return ((EntrySpecificValidation) configEntry.extensionsData()).validators();
|
||||
return entryData;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -173,7 +179,7 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ValidationIssues validate(@NotNull ConfigEntry<T> entry, @Nullable T value) {
|
||||
public <T> ValidationIssues validate(ConfigEntry<T> entry, @Nullable T value) {
|
||||
PathTracking pathTracking = new PathTracking();
|
||||
ValidatingConfigEntryVisitor validatingVisitor = new ValidatingConfigEntryVisitor(pathTracking);
|
||||
|
||||
@@ -182,9 +188,22 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
||||
return validatingVisitor.validationIssues();
|
||||
}
|
||||
|
||||
@Value
|
||||
private static class InternalValidationEntryDataImpl implements InternalValidationEntryData {
|
||||
ConfigEntryValidator completeEntryValidator;
|
||||
@Data
|
||||
private static class CustomEntryData {
|
||||
@Setter(AccessLevel.NONE)
|
||||
private @Nullable List<Middleware<ConfigEntryValidator>> validators;
|
||||
private @Nullable ConfigEntryValidator completeValidator;
|
||||
|
||||
public List<Middleware<ConfigEntryValidator>> validators() {
|
||||
return validators == null ? Collections.emptyList() : validators;
|
||||
}
|
||||
|
||||
public void addValidator(Middleware<ConfigEntryValidator> validator) {
|
||||
if (validators == null) {
|
||||
validators = new ArrayList<>();
|
||||
}
|
||||
validators.add(validator);
|
||||
}
|
||||
}
|
||||
|
||||
private class EntryValidationReaderMiddleware implements Middleware<TweedEntryReader<?, ?>> {
|
||||
@@ -200,23 +219,29 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
||||
|
||||
@Override
|
||||
public TweedEntryReader<?, ?> process(TweedEntryReader<?, ?> inner) {
|
||||
assert readContextValidationIssuesAccess != null && patherExtension != null;
|
||||
|
||||
//noinspection unchecked
|
||||
TweedEntryReader<Object, ConfigEntry<Object>> castedInner = (TweedEntryReader<Object, ConfigEntry<Object>>) inner;
|
||||
return (TweedDataReader reader, ConfigEntry<Object> entry, TweedReadContext context) -> {
|
||||
ValidationIssues validationIssues;
|
||||
if (!context.extensionsData().isPatchworkPartSet(ValidationIssues.class)) {
|
||||
ValidationIssues validationIssues = context.extensionsData().get(readContextValidationIssuesAccess);
|
||||
if (validationIssues == null) {
|
||||
validationIssues = new ValidationIssuesImpl();
|
||||
readContextValidationIssuesExtensionData.set(context.extensionsData(), validationIssues);
|
||||
} else {
|
||||
validationIssues = (ValidationIssues) context.extensionsData();
|
||||
}
|
||||
|
||||
Object value = castedInner.read(reader, entry, context);
|
||||
|
||||
ValidationResult<Object> validationResult = ((InternalValidationEntryData) entry.extensionsData()).completeEntryValidator().validate(entry, value);
|
||||
ConfigEntryValidator entryValidator = entry.extensionsData()
|
||||
.get(customEntryDataAccess)
|
||||
.completeValidator();
|
||||
assert entryValidator != null;
|
||||
|
||||
if (!validationResult.issues().isEmpty() && context.extensionsData().isPatchworkPartSet(PatherData.class)) {
|
||||
String path = ((PatherData) context.extensionsData()).valuePath();
|
||||
ValidationResult<Object> validationResult = entryValidator.validate(entry, value);
|
||||
|
||||
if (!validationResult.issues().isEmpty()) {
|
||||
String path = patherExtension.getPath(context);
|
||||
validationIssues.issuesByPath().put(path, new ValidationIssues.EntryIssues(
|
||||
entry,
|
||||
validationResult.issues()
|
||||
@@ -234,15 +259,19 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
private static class ValidatingConfigEntryVisitor implements ConfigEntryValueVisitor {
|
||||
private class ValidatingConfigEntryVisitor implements ConfigEntryValueVisitor {
|
||||
private final PathTracking pathTracking;
|
||||
private final ValidationIssues validationIssues = new ValidationIssuesImpl();
|
||||
|
||||
@Override
|
||||
public <T> void visitEntry(ConfigEntry<T> entry, T value) {
|
||||
ValidationResult<T> result = ((InternalValidationEntryData) entry.extensionsData()).completeEntryValidator().validate(entry, value);
|
||||
CustomEntryData entryData = entry.extensionsData().get(customEntryDataAccess);
|
||||
assert entryData != null;
|
||||
ConfigEntryValidator entryValidator = entryData.completeValidator();
|
||||
assert entryValidator != null;
|
||||
ValidationResult<T> result = entryValidator.validate(entry, value);
|
||||
if (!result.issues().isEmpty()) {
|
||||
validationIssues.issuesByPath().put(pathTracking.valuePath(), new ValidationIssues.EntryIssues(entry, result.issues()));
|
||||
validationIssues.issuesByPath().put(pathTracking.currentPath(), new ValidationIssues.EntryIssues(entry, result.issues()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,21 @@
|
||||
package de.siphalor.tweed5.defaultextensions.validationfallback.api;
|
||||
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.validationfallback.impl.ValidationFallbackExtensionImpl;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public interface ValidationFallbackExtension extends TweedExtension {
|
||||
Class<? extends ValidationFallbackExtension> DEFAULT = ValidationFallbackExtensionImpl.class;
|
||||
|
||||
static <C extends ConfigEntry<T>, T> Consumer<C> validationFallbackValue(T value) {
|
||||
return entry -> {
|
||||
ValidationFallbackExtension extension = entry.container().extension(ValidationFallbackExtension.class)
|
||||
.orElseThrow(() -> new IllegalStateException("ValidationFallbackExtension is not registered"));
|
||||
extension.setFallbackValue(entry, value);
|
||||
};
|
||||
}
|
||||
|
||||
<T> void setFallbackValue(ConfigEntry<T> entry, T value);
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
package de.siphalor.tweed5.defaultextensions.validationfallback.api;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public interface ValidationFallbackValue {
|
||||
@Nullable Object validationFallbackValue();
|
||||
}
|
||||
@@ -10,7 +10,8 @@ import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssu
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssueLevel;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult;
|
||||
import de.siphalor.tweed5.defaultextensions.validationfallback.api.ValidationFallbackExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.validationfallback.api.ValidationFallbackValue;
|
||||
import de.siphalor.tweed5.patchwork.api.PatchworkPartAccess;
|
||||
import lombok.Data;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -20,8 +21,11 @@ import java.util.stream.Collectors;
|
||||
|
||||
@AutoService(ValidationFallbackExtension.class)
|
||||
public class ValidationFallbackExtensionImpl implements ValidationFallbackExtension, ValidationProvidingExtension {
|
||||
|
||||
private final PatchworkPartAccess<CustomEntryData> customEntryDataAccess;
|
||||
|
||||
public ValidationFallbackExtensionImpl(TweedExtensionSetupContext context) {
|
||||
context.registerEntryExtensionData(ValidationFallbackValue.class);
|
||||
customEntryDataAccess = context.registerEntryExtensionData(CustomEntryData.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -29,12 +33,31 @@ public class ValidationFallbackExtensionImpl implements ValidationFallbackExtens
|
||||
return "validation-fallback";
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void setFallbackValue(ConfigEntry<T> entry, T value) {
|
||||
getOrCreateCustomEntryData(entry).fallbackValue(value);
|
||||
}
|
||||
|
||||
private CustomEntryData getOrCreateCustomEntryData(ConfigEntry<?> entry) {
|
||||
CustomEntryData customEntryData = entry.extensionsData().get(customEntryDataAccess);
|
||||
if (customEntryData == null) {
|
||||
customEntryData = new CustomEntryData();
|
||||
entry.extensionsData().set(customEntryDataAccess, customEntryData);
|
||||
}
|
||||
return customEntryData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Middleware<ConfigEntryValidator> validationMiddleware() {
|
||||
return new ValidationFallbackMiddleware();
|
||||
}
|
||||
|
||||
private static class ValidationFallbackMiddleware implements Middleware<ConfigEntryValidator> {
|
||||
@Data
|
||||
private static class CustomEntryData {
|
||||
@Nullable Object fallbackValue;
|
||||
}
|
||||
|
||||
private class ValidationFallbackMiddleware implements Middleware<ConfigEntryValidator> {
|
||||
@Override
|
||||
public String id() {
|
||||
return "validation-fallback";
|
||||
@@ -59,13 +82,14 @@ public class ValidationFallbackExtensionImpl implements ValidationFallbackExtens
|
||||
if (!result.hasError()) {
|
||||
return result;
|
||||
}
|
||||
if (!configEntry.extensionsData().isPatchworkPartSet(ValidationFallbackValue.class)) {
|
||||
CustomEntryData entryData = configEntry.extensionsData().get(customEntryDataAccess);
|
||||
if (entryData == null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Object fallbackValue = ((ValidationFallbackValue) configEntry.extensionsData()).validationFallbackValue();
|
||||
Object fallbackValue = entryData.fallbackValue();
|
||||
if (fallbackValue != null) {
|
||||
if (fallbackValue.getClass() == configEntry.valueClass()) {
|
||||
if (configEntry.valueClass().isInstance(fallbackValue)) {
|
||||
//noinspection unchecked
|
||||
fallbackValue = configEntry.deepCopy((T) fallbackValue);
|
||||
} else {
|
||||
@@ -90,12 +114,11 @@ public class ValidationFallbackExtensionImpl implements ValidationFallbackExtens
|
||||
|
||||
@Override
|
||||
public <T> String description(ConfigEntry<T> configEntry) {
|
||||
if (!configEntry.extensionsData().isPatchworkPartSet(ValidationFallbackValue.class)) {
|
||||
CustomEntryData entryData = configEntry.extensionsData().get(customEntryDataAccess);
|
||||
if (entryData == null) {
|
||||
return inner.description(configEntry);
|
||||
}
|
||||
return inner.description(configEntry) +
|
||||
"\n\nDefault/Fallback value: " +
|
||||
((ValidationFallbackValue) configEntry.extensionsData()).validationFallbackValue();
|
||||
return inner.description(configEntry) + "\n\nDefault/Fallback value: " + entryData.fallbackValue();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,27 +1,20 @@
|
||||
package de.siphalor.tweed5.defaultextensions.comment.impl;
|
||||
|
||||
import de.siphalor.tweed5.core.api.extension.EntryExtensionsData;
|
||||
import de.siphalor.tweed5.core.api.extension.RegisteredExtensionData;
|
||||
import de.siphalor.tweed5.core.api.entry.CompoundConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.entry.SimpleConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
||||
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
||||
import de.siphalor.tweed5.core.impl.DefaultConfigContainer;
|
||||
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
|
||||
import de.siphalor.tweed5.core.impl.entry.StaticMapCompoundConfigEntryImpl;
|
||||
import de.siphalor.tweed5.data.extension.api.EntryReaderWriterDefinition;
|
||||
import de.siphalor.tweed5.data.extension.api.ReadWriteExtension;
|
||||
import de.siphalor.tweed5.data.extension.api.TweedEntryReader;
|
||||
import de.siphalor.tweed5.data.extension.api.TweedEntryWriter;
|
||||
import de.siphalor.tweed5.data.extension.api.readwrite.TweedEntryReaderWriter;
|
||||
import de.siphalor.tweed5.data.extension.api.readwrite.TweedEntryReaderWriters;
|
||||
import de.siphalor.tweed5.data.hjson.HjsonCommentType;
|
||||
import de.siphalor.tweed5.data.hjson.HjsonWriter;
|
||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentModifyingExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentProducer;
|
||||
import de.siphalor.tweed5.defaultextensions.comment.api.EntryComment;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Value;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.jspecify.annotations.NullUnmarked;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -31,6 +24,9 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static de.siphalor.tweed5.data.extension.api.ReadWriteExtension.entryReaderWriter;
|
||||
import static de.siphalor.tweed5.data.extension.api.readwrite.TweedEntryReaderWriters.*;
|
||||
import static de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension.baseComment;
|
||||
import static de.siphalor.tweed5.testutils.MapTestUtils.sequencedMap;
|
||||
import static java.util.Map.entry;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
@@ -38,44 +34,44 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||
@NullUnmarked
|
||||
class CommentExtensionImplTest {
|
||||
|
||||
private DefaultConfigContainer<Map<String, Object>> configContainer;
|
||||
private StaticMapCompoundConfigEntryImpl<Map<String, Object>> rootEntry;
|
||||
private SimpleConfigEntryImpl<Integer> intEntry;
|
||||
private SimpleConfigEntryImpl<String> stringEntry;
|
||||
private SimpleConfigEntryImpl<Long> noCommentEntry;
|
||||
private DefaultConfigContainer<@NonNull Map<String, Object>> configContainer;
|
||||
private CompoundConfigEntry<Map<String, Object>> rootEntry;
|
||||
private SimpleConfigEntry<Integer> intEntry;
|
||||
private SimpleConfigEntry<String> stringEntry;
|
||||
private SimpleConfigEntry<Long> noCommentEntry;
|
||||
|
||||
@SafeVarargs
|
||||
final void setupContainer(Class<? extends TweedExtension>... extraExtensions) {
|
||||
configContainer = new DefaultConfigContainer<>();
|
||||
|
||||
configContainer.registerExtension(CommentExtension.DEFAULT);
|
||||
configContainer.registerExtension(ReadWriteExtension.DEFAULT);
|
||||
configContainer.registerExtensions(extraExtensions);
|
||||
configContainer.finishExtensionSetup();
|
||||
|
||||
intEntry = new SimpleConfigEntryImpl<>(configContainer, Integer.class);
|
||||
stringEntry = new SimpleConfigEntryImpl<>(configContainer, String.class);
|
||||
noCommentEntry = new SimpleConfigEntryImpl<>(configContainer, Long.class);
|
||||
intEntry = new SimpleConfigEntryImpl<>(configContainer, Integer.class)
|
||||
.apply(entryReaderWriter(intReaderWriter()))
|
||||
.apply(baseComment("It is an integer"));
|
||||
stringEntry = new SimpleConfigEntryImpl<>(configContainer, String.class)
|
||||
.apply(entryReaderWriter(stringReaderWriter()))
|
||||
.apply(baseComment("It is a string"));
|
||||
noCommentEntry = new SimpleConfigEntryImpl<>(configContainer, Long.class)
|
||||
.apply(entryReaderWriter(longReaderWriter()));
|
||||
|
||||
//noinspection unchecked
|
||||
rootEntry = new StaticMapCompoundConfigEntryImpl<>(
|
||||
configContainer,
|
||||
((Class<Map<String, Object>>)(Class<?>) Map.class),
|
||||
((Class<Map<String, Object>>) (Class<?>) Map.class),
|
||||
LinkedHashMap::new,
|
||||
sequencedMap(List.of(
|
||||
entry("int", intEntry),
|
||||
entry("string", stringEntry),
|
||||
entry("noComment", noCommentEntry)
|
||||
))
|
||||
);
|
||||
)))
|
||||
.apply(entryReaderWriter(compoundReaderWriter()))
|
||||
.apply(baseComment("This is the root value.\nIt is the topmost value in the tree."));
|
||||
|
||||
configContainer.attachTree(rootEntry);
|
||||
|
||||
//noinspection unchecked
|
||||
RegisteredExtensionData<EntryExtensionsData, EntryComment> commentData = (RegisteredExtensionData<EntryExtensionsData, EntryComment>) configContainer.entryDataExtensions().get(EntryComment.class);
|
||||
|
||||
commentData.set(rootEntry.extensionsData(), new CommentImpl("This is the root value.\nIt is the topmost value in the tree."));
|
||||
commentData.set(intEntry.extensionsData(), new CommentImpl("It is an integer"));
|
||||
commentData.set(stringEntry.extensionsData(), new CommentImpl("It is a string"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -102,8 +98,7 @@ class CommentExtensionImplTest {
|
||||
|
||||
@Test
|
||||
void simpleCommentsInHjson() {
|
||||
setupContainer(ReadWriteExtension.DEFAULT);
|
||||
setupReadWriteTypes();
|
||||
setupContainer();
|
||||
configContainer.initialize();
|
||||
|
||||
Map<String, Object> value = new HashMap<>();
|
||||
@@ -134,21 +129,6 @@ class CommentExtensionImplTest {
|
||||
""", output.toString());
|
||||
}
|
||||
|
||||
private void setupReadWriteTypes() {
|
||||
//noinspection unchecked
|
||||
var readerWriterData = (RegisteredExtensionData<EntryExtensionsData, EntryReaderWriterDefinition>) configContainer.entryDataExtensions().get(EntryReaderWriterDefinition.class);
|
||||
|
||||
readerWriterData.set(rootEntry.extensionsData(), new TrivialEntryReaderWriterDefinition(TweedEntryReaderWriters.compoundReaderWriter()));
|
||||
readerWriterData.set(intEntry.extensionsData(), new TrivialEntryReaderWriterDefinition(TweedEntryReaderWriters.intReaderWriter()));
|
||||
readerWriterData.set(stringEntry.extensionsData(), new TrivialEntryReaderWriterDefinition(TweedEntryReaderWriters.stringReaderWriter()));
|
||||
readerWriterData.set(noCommentEntry.extensionsData(), new TrivialEntryReaderWriterDefinition(TweedEntryReaderWriters.longReaderWriter()));
|
||||
}
|
||||
|
||||
@Value
|
||||
private static class CommentImpl implements EntryComment {
|
||||
String comment;
|
||||
}
|
||||
|
||||
@NoArgsConstructor
|
||||
public static class TestCommentModifyingExtension implements TweedExtension, CommentModifyingExtension {
|
||||
@Override
|
||||
@@ -158,7 +138,7 @@ class CommentExtensionImplTest {
|
||||
|
||||
@Override
|
||||
public Middleware<CommentProducer> commentMiddleware() {
|
||||
return new Middleware<CommentProducer>() {
|
||||
return new Middleware<>() {
|
||||
@Override
|
||||
public String id() {
|
||||
return "test";
|
||||
@@ -171,19 +151,4 @@ class CommentExtensionImplTest {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
private static class TrivialEntryReaderWriterDefinition implements EntryReaderWriterDefinition {
|
||||
private final TweedEntryReaderWriter<?, ?> readerWriter;
|
||||
|
||||
@Override
|
||||
public TweedEntryReader<?, ?> reader() {
|
||||
return readerWriter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TweedEntryWriter<?, ?> writer() {
|
||||
return readerWriter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +1,39 @@
|
||||
package de.siphalor.tweed5.defaultextensions.validation.impl;
|
||||
|
||||
import de.siphalor.tweed5.core.api.entry.CompoundConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.extension.EntryExtensionsData;
|
||||
import de.siphalor.tweed5.core.api.extension.RegisteredExtensionData;
|
||||
import de.siphalor.tweed5.core.api.entry.SimpleConfigEntry;
|
||||
import de.siphalor.tweed5.core.impl.DefaultConfigContainer;
|
||||
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
|
||||
import de.siphalor.tweed5.core.impl.entry.StaticMapCompoundConfigEntryImpl;
|
||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.comment.api.EntryComment;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.EntrySpecificValidation;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssue;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssueLevel;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssues;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.validators.NumberRangeValidator;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.validators.SimpleValidatorMiddleware;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension.baseComment;
|
||||
import static de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension.validators;
|
||||
import static de.siphalor.tweed5.testutils.MapTestUtils.sequencedMap;
|
||||
import static java.util.Map.entry;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class ValidationExtensionImplTest {
|
||||
private DefaultConfigContainer<Map<String, Object>> configContainer;
|
||||
private StaticMapCompoundConfigEntryImpl<Map<String, Object>> rootEntry;
|
||||
private SimpleConfigEntryImpl<Byte> byteEntry;
|
||||
private SimpleConfigEntryImpl<Integer> intEntry;
|
||||
private SimpleConfigEntryImpl<Double> doubleEntry;
|
||||
private CompoundConfigEntry<Map<String, Object>> rootEntry;
|
||||
private SimpleConfigEntry<Byte> byteEntry;
|
||||
private SimpleConfigEntry<Integer> intEntry;
|
||||
private SimpleConfigEntry<Double> doubleEntry;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
@@ -41,9 +43,13 @@ class ValidationExtensionImplTest {
|
||||
configContainer.registerExtension(ValidationExtension.DEFAULT);
|
||||
configContainer.finishExtensionSetup();
|
||||
|
||||
byteEntry = new SimpleConfigEntryImpl<>(configContainer, Byte.class);
|
||||
intEntry = new SimpleConfigEntryImpl<>(configContainer, Integer.class);
|
||||
doubleEntry = new SimpleConfigEntryImpl<>(configContainer, Double.class);
|
||||
byteEntry = new SimpleConfigEntryImpl<>(configContainer, Byte.class)
|
||||
.apply(validators(new NumberRangeValidator<>(Byte.class, (byte) 10, (byte) 100)));
|
||||
intEntry = new SimpleConfigEntryImpl<>(configContainer, Integer.class)
|
||||
.apply(validators(new NumberRangeValidator<>(Integer.class, null, 123)))
|
||||
.apply(baseComment("This is the main comment!"));
|
||||
doubleEntry = new SimpleConfigEntryImpl<>(configContainer, Double.class)
|
||||
.apply(validators(new NumberRangeValidator<>(Double.class, 0.5, null)));
|
||||
|
||||
//noinspection unchecked
|
||||
rootEntry = new StaticMapCompoundConfigEntryImpl<>(
|
||||
@@ -59,25 +65,6 @@ class ValidationExtensionImplTest {
|
||||
|
||||
|
||||
configContainer.attachTree(rootEntry);
|
||||
|
||||
//noinspection unchecked
|
||||
RegisteredExtensionData<EntryExtensionsData, EntryComment> commentData = (RegisteredExtensionData<EntryExtensionsData, EntryComment>) configContainer.entryDataExtensions().get(EntryComment.class);
|
||||
commentData.set(intEntry.extensionsData(), () -> "This is the main comment!");
|
||||
//noinspection unchecked
|
||||
RegisteredExtensionData<EntryExtensionsData, EntrySpecificValidation> entrySpecificValidation = (RegisteredExtensionData<EntryExtensionsData, EntrySpecificValidation>) configContainer.entryDataExtensions().get(EntrySpecificValidation.class);
|
||||
entrySpecificValidation.set(
|
||||
byteEntry.extensionsData(),
|
||||
() -> Collections.singleton(new SimpleValidatorMiddleware("range", new NumberRangeValidator<>(Byte.class, (byte) 10, (byte) 100)))
|
||||
);
|
||||
entrySpecificValidation.set(
|
||||
intEntry.extensionsData(),
|
||||
() -> Collections.singleton(new SimpleValidatorMiddleware("range", new NumberRangeValidator<>(Integer.class, null, 123)))
|
||||
);
|
||||
entrySpecificValidation.set(
|
||||
doubleEntry.extensionsData(),
|
||||
() -> Collections.singleton(new SimpleValidatorMiddleware("range", new NumberRangeValidator<>(Double.class, 0.5, null)))
|
||||
);
|
||||
|
||||
configContainer.initialize();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,30 +1,21 @@
|
||||
package de.siphalor.tweed5.defaultextensions.validationfallback.impl;
|
||||
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.extension.EntryExtensionsData;
|
||||
import de.siphalor.tweed5.core.api.extension.RegisteredExtensionData;
|
||||
import de.siphalor.tweed5.core.api.entry.SimpleConfigEntry;
|
||||
import de.siphalor.tweed5.core.impl.DefaultConfigContainer;
|
||||
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
|
||||
import de.siphalor.tweed5.data.extension.api.EntryReaderWriterDefinition;
|
||||
import de.siphalor.tweed5.data.extension.api.ReadWriteExtension;
|
||||
import de.siphalor.tweed5.data.extension.api.TweedEntryReader;
|
||||
import de.siphalor.tweed5.data.extension.api.TweedEntryWriter;
|
||||
import de.siphalor.tweed5.data.extension.api.readwrite.TweedEntryReaderWriters;
|
||||
import de.siphalor.tweed5.data.hjson.HjsonCommentType;
|
||||
import de.siphalor.tweed5.data.hjson.HjsonLexer;
|
||||
import de.siphalor.tweed5.data.hjson.HjsonReader;
|
||||
import de.siphalor.tweed5.data.hjson.HjsonWriter;
|
||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.ConfigEntryValidator;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.EntrySpecificValidation;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssue;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssueLevel;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.validators.SimpleValidatorMiddleware;
|
||||
import de.siphalor.tweed5.defaultextensions.validationfallback.api.ValidationFallbackExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.validationfallback.api.ValidationFallbackValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -33,18 +24,19 @@ import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import static de.siphalor.tweed5.data.extension.api.ReadWriteExtension.*;
|
||||
import static de.siphalor.tweed5.data.extension.api.readwrite.TweedEntryReaderWriters.*;
|
||||
import static de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension.validators;
|
||||
import static de.siphalor.tweed5.defaultextensions.validationfallback.api.ValidationFallbackExtension.validationFallbackValue;
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class ValidationFallbackExtensionImplTest {
|
||||
private DefaultConfigContainer<Integer> configContainer;
|
||||
private SimpleConfigEntryImpl<Integer> intEntry;
|
||||
private SimpleConfigEntry<Integer> intEntry;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
configContainer = new DefaultConfigContainer<>();
|
||||
@@ -55,92 +47,82 @@ class ValidationFallbackExtensionImplTest {
|
||||
|
||||
configContainer.finishExtensionSetup();
|
||||
|
||||
intEntry = new SimpleConfigEntryImpl<>(configContainer, Integer.class);
|
||||
intEntry = new SimpleConfigEntryImpl<>(configContainer, Integer.class)
|
||||
.apply(entryReaderWriter(nullableReader(intReaderWriter()), nullableWriter(intReaderWriter())))
|
||||
.apply(validators(
|
||||
new ConfigEntryValidator() {
|
||||
@Override
|
||||
public <T extends @Nullable Object> ValidationResult<T> validate(ConfigEntry<T> configEntry, @Nullable T value) {
|
||||
if (value == null) {
|
||||
return ValidationResult.withIssues(
|
||||
null, Collections.singleton(
|
||||
new ValidationIssue(
|
||||
"Value must not be null",
|
||||
ValidationIssueLevel.ERROR
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
return ValidationResult.ok(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> String description(ConfigEntry<T> configEntry) {
|
||||
return "Must not be null.";
|
||||
}
|
||||
},
|
||||
new ConfigEntryValidator() {
|
||||
|
||||
@Override
|
||||
public <T> ValidationResult<T> validate(ConfigEntry<T> configEntry, @Nullable T value) {
|
||||
assert value != null;
|
||||
int intValue = (int) value;
|
||||
if (intValue < 1) {
|
||||
return ValidationResult.withIssues(
|
||||
value,
|
||||
Collections.singleton(new ValidationIssue(
|
||||
"Must be greater or equal to 1",
|
||||
ValidationIssueLevel.ERROR
|
||||
))
|
||||
);
|
||||
}
|
||||
if (intValue > 6) {
|
||||
return ValidationResult.withIssues(
|
||||
value,
|
||||
Collections.singleton(new ValidationIssue(
|
||||
"Must be smaller or equal to 6",
|
||||
ValidationIssueLevel.ERROR
|
||||
))
|
||||
);
|
||||
}
|
||||
return ValidationResult.ok(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> String description(ConfigEntry<T> configEntry) {
|
||||
return "Must be between 1 and 6";
|
||||
}
|
||||
}
|
||||
))
|
||||
.apply(validationFallbackValue(3));
|
||||
|
||||
configContainer.attachTree(intEntry);
|
||||
|
||||
RegisteredExtensionData<EntryExtensionsData, EntrySpecificValidation> entrySpecificValidation = (RegisteredExtensionData<EntryExtensionsData, EntrySpecificValidation>) configContainer.entryDataExtensions().get(EntrySpecificValidation.class);
|
||||
entrySpecificValidation.set(intEntry.extensionsData(), () -> Arrays.asList(
|
||||
new SimpleValidatorMiddleware("non-null", new ConfigEntryValidator() {
|
||||
@Override
|
||||
public <T> ValidationResult<T> validate(ConfigEntry<T> configEntry, @Nullable T value) {
|
||||
if (value == null) {
|
||||
return ValidationResult.withIssues(null, Collections.singleton(
|
||||
new ValidationIssue("Value must not be null", ValidationIssueLevel.ERROR)
|
||||
));
|
||||
}
|
||||
return ValidationResult.ok(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull <T> String description(ConfigEntry<T> configEntry) {
|
||||
return "Must not be null.";
|
||||
}
|
||||
}),
|
||||
new SimpleValidatorMiddleware("range", new ConfigEntryValidator() {
|
||||
@Override
|
||||
public <T> ValidationResult<T> validate(ConfigEntry<T> configEntry, @Nullable T value) {
|
||||
Integer intValue = (Integer) value;
|
||||
if (intValue < 1) {
|
||||
return ValidationResult.withIssues(value, Collections.singleton(new ValidationIssue("Must be greater or equal to 1", ValidationIssueLevel.ERROR)));
|
||||
}
|
||||
if (intValue > 6) {
|
||||
return ValidationResult.withIssues(value, Collections.singleton(new ValidationIssue("Must be smaller or equal to 6", ValidationIssueLevel.ERROR)));
|
||||
}
|
||||
return ValidationResult.ok(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull <T> String description(ConfigEntry<T> configEntry) {
|
||||
return "Must be between 1 and 6";
|
||||
}
|
||||
}) {
|
||||
@Override
|
||||
public Set<String> mustComeAfter() {
|
||||
return Collections.singleton("non-null");
|
||||
}
|
||||
}
|
||||
));
|
||||
|
||||
RegisteredExtensionData<EntryExtensionsData, ValidationFallbackValue> validationFallbackValue = (RegisteredExtensionData<EntryExtensionsData, ValidationFallbackValue>) configContainer.entryDataExtensions().get(ValidationFallbackValue.class);
|
||||
validationFallbackValue.set(intEntry.extensionsData(), () -> 3);
|
||||
|
||||
RegisteredExtensionData<EntryExtensionsData, EntryReaderWriterDefinition> readerWriterData = (RegisteredExtensionData<EntryExtensionsData, EntryReaderWriterDefinition>) configContainer.entryDataExtensions().get(EntryReaderWriterDefinition.class);
|
||||
readerWriterData.set(intEntry.extensionsData(), new EntryReaderWriterDefinition() {
|
||||
@Override
|
||||
public TweedEntryReader<?, ?> reader() {
|
||||
return TweedEntryReaderWriters.nullableReader(TweedEntryReaderWriters.intReaderWriter());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TweedEntryWriter<?, ?> writer() {
|
||||
return TweedEntryReaderWriters.nullableWriter(TweedEntryReaderWriters.intReaderWriter());
|
||||
}
|
||||
});
|
||||
|
||||
configContainer.initialize();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"0", "7", "123", "null"})
|
||||
void fallbackTriggers(String input) {
|
||||
ReadWriteExtension readWriteExtension = configContainer.extension(ReadWriteExtension.class).orElseThrow();
|
||||
Integer result = assertDoesNotThrow(() -> readWriteExtension.read(
|
||||
new HjsonReader(new HjsonLexer(new StringReader(input))),
|
||||
intEntry,
|
||||
readWriteExtension.createReadWriteContextExtensionsData()
|
||||
));
|
||||
Integer result = intEntry.call(read(new HjsonReader(new HjsonLexer(new StringReader(input)))));
|
||||
assertEquals(3, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void description() {
|
||||
ReadWriteExtension readWriteExtension = configContainer.extension(ReadWriteExtension.class).orElseThrow();
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
assertDoesNotThrow(() -> readWriteExtension.write(
|
||||
intEntry.apply(write(
|
||||
new HjsonWriter(stringWriter, new HjsonWriter.Options().multilineCommentType(HjsonCommentType.SLASHES)),
|
||||
5,
|
||||
intEntry,
|
||||
readWriteExtension.createReadWriteContextExtensionsData()
|
||||
5
|
||||
));
|
||||
|
||||
assertEquals(
|
||||
|
||||
Reference in New Issue
Block a user