1
mirror of https://github.com/CarmJos/EasyConfiguration.git synced 2026-06-04 18:48:20 +08:00

Compare commits

...

20 Commits

Author SHA1 Message Date
renovate[bot] 5ae756929a fix(deps): update dependency cc.carm.lib:yamlcommentwriter to v1.2.0 2025-02-17 18:28:00 +08:00
carm a9e80aecce fix(text): Fixed wrong type of text 2025-02-17 18:28:00 +08:00
carm 477f0d11bc fix(text): Fixed wrong type of text 2025-02-17 06:43:30 +08:00
renovate[bot] 53ff38a76f fix(deps): update dependency cc.carm.lib:yamlcommentwriter to v1.2.0 2025-02-17 05:24:09 +08:00
carm c32bea3864 fix(builder): Fixed wrong type of serializer 2025-02-17 04:48:15 +08:00
carm 15823bb076 fix(builder): Fixed wrong type of serializer 2025-02-17 04:47:23 +08:00
renovate[bot] f303f56199 fix(deps): update dependency cc.carm.lib:yamlcommentwriter to v1.2.0 2025-02-17 04:27:50 +08:00
carm 22f2674e7c feat(text): Separated the text handler 2025-02-17 04:26:22 +08:00
carm 9eb9c9e13d feat(parser): Supported more insert functions 2025-02-17 03:14:40 +08:00
carm 616314c7f0 feat(parser): Supported more insert functions 2025-02-17 03:13:35 +08:00
carm 05f504a347 feat(parser): Supported parse functions 2025-02-17 02:46:18 +08:00
carm bf6ea97b99 feaT(unit): Add unit meta 2025-02-17 01:40:41 +08:00
carm 9847399e56 feat: Version update to 4.0.1 2025-02-17 00:33:41 +08:00
carm 18515d4a78 refactor(comment): Extract common comment functions 2025-02-17 00:12:29 +08:00
carm 9f1fc5bf90 refactor(comment): Extract common comment functions 2025-02-17 00:11:56 +08:00
carm e7847b2166 feat: Version update to 4.0.1 2025-02-16 23:51:18 +08:00
carm 69cec281be feat: Version update to 4.0.1 2025-02-16 23:47:22 +08:00
carm 28dc9b9e55 feat(text): Implement the ConfiguredText for simply text/msg functions. 2025-02-16 23:46:31 +08:00
LSeng c60ba074d9 fix(comment): Fixed wrong behavior of inline regex comments 2025-02-16 21:59:03 +08:00
carm e88bf301cc ci(javadoc): Fixed javadoc deployment 2025-02-16 02:31:10 +08:00
37 changed files with 1206 additions and 70 deletions
+1 -1
View File
@@ -40,7 +40,7 @@ jobs:
run: |
rm -rf docs
mkdir -vp docs
cp -vrf core/target/apidocs/* docs/
cp -vrf core/target/reports/apidocs/* docs/
cp -vrf .doc/JAVADOC-README.md docs/README.md
- name: "Generate the Javadoc sitemap"
+1 -1
View File
@@ -1,3 +1,3 @@
/.idea/
.idea/
**/target/
**.iml
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>easyconfiguration-parent</artifactId>
<groupId>cc.carm.lib</groupId>
<version>4.0.0</version>
<version>4.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<properties>
@@ -3,8 +3,8 @@ package cc.carm.lib.configuration.builder.impl;
import cc.carm.lib.configuration.adapter.ValueAdapter;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.builder.CommonConfigBuilder;
import cc.carm.lib.configuration.function.DataConsumer;
import cc.carm.lib.configuration.function.DataFunction;
import cc.carm.lib.configuration.function.ValueConsumer;
import cc.carm.lib.configuration.function.ValueHandler;
import cc.carm.lib.configuration.source.section.ConfigureSection;
import cc.carm.lib.configuration.value.ConfigValue;
@@ -34,28 +34,30 @@ public abstract class AbstractSectionBuilder<
this.serializer = serializer;
}
public @NotNull SELF parse(DataFunction<ConfigureSection, PARAM> valueParser) {
public @NotNull SELF parse(@NotNull DataFunction<ConfigureSection, PARAM> valueParser) {
return parse((p, section) -> valueParser.handle(section));
}
public @NotNull SELF parse(ValueHandler<ConfigureSection, PARAM> valueParser) {
public @NotNull SELF parse(@NotNull ValueHandler<ConfigureSection, PARAM> valueParser) {
this.parser = valueParser;
return self();
}
public @NotNull SELF serialize(DataFunction<PARAM, ? extends Map<String, Object>> serializer) {
return serialize((p, value) -> serializer.handle(value));
}
public @NotNull SELF serialize(ValueHandler<PARAM, ? extends Map<String, Object>> serializer) {
public @NotNull SELF serialize(@NotNull ValueHandler<PARAM, ? extends Map<String, Object>> serializer) {
this.serializer = serializer;
return self();
}
public @NotNull SELF serialize(DataConsumer<Map<String, Object>> serializer) {
public @NotNull SELF serialize(@NotNull DataFunction<PARAM, ? extends Map<String, Object>> serializer) {
return serialize((p, value) -> {
return serializer.handle(value);
});
}
public @NotNull SELF serialize(@NotNull ValueConsumer<Map<String, Object>, PARAM> serializer) {
return serialize((h, value) -> {
Map<String, Object> map = new LinkedHashMap<>();
serializer.accept(map);
serializer.accept(h, map, value);
return map;
});
}
@@ -19,9 +19,9 @@ public abstract class AbstractSourceBuilder<
protected @NotNull ValueHandler<PARAM, SOURCE> valueSerializer;
protected AbstractSourceBuilder(@NotNull ValueType<V> type,
@NotNull ValueType<SOURCE> sourceType, @NotNull ValueType<PARAM> paramType,
@NotNull ValueHandler<SOURCE, PARAM> parser,
@NotNull ValueHandler<PARAM, SOURCE> serializer) {
@NotNull ValueType<SOURCE> sourceType, @NotNull ValueType<PARAM> paramType,
@NotNull ValueHandler<SOURCE, PARAM> parser,
@NotNull ValueHandler<PARAM, SOURCE> serializer) {
super(type);
this.sourceType = sourceType;
this.paramType = paramType;
@@ -29,7 +29,7 @@ public abstract class AbstractSourceBuilder<
this.valueSerializer = serializer;
}
public @NotNull SELF parse(DataFunction<SOURCE, PARAM> parser) {
public @NotNull SELF parse(@NotNull DataFunction<SOURCE, PARAM> parser) {
return parse((p, source) -> parser.handle(source));
}
@@ -0,0 +1,21 @@
package cc.carm.lib.configuration.function;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull;
@FunctionalInterface
public interface ValueConsumer<U, T> {
void accept(@NotNull ConfigurationHolder<?> holder, @NotNull U unit, @NotNull T data) throws Exception;
default ValueConsumer<U, T> andThen(ValueConsumer<? super U, ? super T> after) {
return (holder, unit, data) -> {
accept(holder, unit, data);
after.accept(holder, unit, data);
};
}
}
@@ -3,6 +3,7 @@ package cc.carm.lib.configuration.source.loader;
import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
import cc.carm.lib.configuration.source.meta.StandardMeta;
import cc.carm.lib.configuration.source.option.StandardOptions;
import cc.carm.lib.configuration.value.ConfigValue;
import org.jetbrains.annotations.NotNull;
@@ -168,6 +169,7 @@ public class ConfigurationInitializer {
String path = getFieldPath(holder, parent, field);
if (path == null) return;
value.initialize(holder, path);
holder.metadata(path).set(StandardMeta.UNIT, true); // Mark the minimal config value unit.
try {
this.fieldInitializer.whenInitialize(holder, path, field);
} catch (Exception e) {
@@ -0,0 +1,10 @@
package cc.carm.lib.configuration.source.meta;
public interface StandardMeta {
/**
* To mark the {@link cc.carm.lib.configuration.value.ConfigValue} as a minimal unit path.
*/
ConfigurationMetadata<Boolean> UNIT = ConfigurationMetadata.of(false);
}
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>easyconfiguration-parent</artifactId>
<groupId>cc.carm.lib</groupId>
<version>4.0.0</version>
<version>4.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<properties>
@@ -46,8 +46,6 @@ public interface DemoConfiguration extends Configuration {
@ConfigPath("registered_users") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。
@HeaderComments({"Section类型数据测试"}) // 通过注解给配置添加注释。
@InlineComment("默认地注释会加到Section的首行末尾") // 通过注解给配置添加注释。
@InlineComment(value = "用户名(匹配注释)", regex = "name") // 通过注解给配置添加注释。
@InlineComment(value = "信息", regex = "info.*") // 通过注解给配置添加注释。
ConfiguredList<UserRecord> ALLOWLISTS = ConfiguredList.builderOf(UserRecord.class).fromSection()
.parse(UserRecord::deserialize).serialize(UserRecord::serialize)
.defaults(UserRecord.CARM).build();
@@ -81,6 +79,7 @@ public interface DemoConfiguration extends Configuration {
.build();
@HeaderComments({"内部类的内部类测试", "通过这种方式,您可以轻易实现多层次的配置文件结构"})
@FooterComments({"-------------"})
public interface That extends Configuration {
ConfiguredList<UUID> OPERATORS = ConfiguredList
@@ -18,6 +18,8 @@ public class RegistryConfig implements Configuration {
@ConfigPath("test.user") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。
@FooterComments({"12313213212"})
@InlineComment(value = "用户名(匹配注释)", regex = "name") // 通过注解给配置添加注释。
@InlineComment(value = "信息", regex = {"info.*", "info.game.*"}) // 通过注解给配置添加注释。
public final ConfigValue<UserRecord> TEST_MODEL = ConfiguredValue.builderOf(UserRecord.class).fromSection()
.defaults(new UserRecord("Carm", UUID.randomUUID()))
.parse((holder, section) -> UserRecord.deserialize(section))
+1 -1
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId>
<version>4.0.0</version>
<version>4.0.1</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
@@ -33,7 +33,7 @@ public @interface InlineComment {
* If the regex is not empty, the comment will be added to
* all sub paths if the regex matches the value.
* If the regex is empty, the comment will be added to the current path.
* <p> e.g. for section, set <b>{"^foo", "*", "bar"}</b> will be set like
* <p> e.g. for section, set <b>"foo.*.bar"</b> will be set like
* <blockquote><pre>
* section:
* foo:
@@ -0,0 +1,66 @@
package cc.carm.lib.configuration.commentable;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
import cc.carm.lib.configuration.source.option.StandardOptions;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Pattern;
public class Commentable {
private Commentable() {
throw new UnsupportedOperationException();
}
public static void registerMeta(@NotNull ConfigurationInitializer initializer) {
CommentableMeta.register(initializer);
}
public static @Nullable String getInlineComment(@NotNull ConfigurationHolder<?> holder, @NotNull String path) {
String comment = getInlineComment(holder, path, null);
if (comment != null) return comment;
String sep = String.valueOf(holder.options().get(StandardOptions.PATH_SEPARATOR));
// If the comment is not found, try to get the comment from the parent section
String[] keys = path.split(Pattern.quote(sep));
if (keys.length == 1) return null;
// Try every possible parent key&child key combination
for (int i = 1; i < keys.length; i++) {
String parentKey = String.join(sep, Arrays.copyOfRange(keys, 0, i));
String childKey = String.join(sep, Arrays.copyOfRange(keys, i, keys.length));
comment = getInlineComment(holder, parentKey, childKey);
if (comment != null) return comment;
}
return null;
}
public static @Nullable String getInlineComment(@NotNull ConfigurationHolder<?> holder, @NotNull String path, @Nullable String sectionKey) {
Map<String, String> pathComment = holder.metadata(path).get(CommentableMeta.INLINE);
if (pathComment == null || pathComment.isEmpty()) return null;
if (sectionKey == null) return pathComment.get(null);
for (Map.Entry<String/*regex*/, String/*content*/> entry : pathComment.entrySet()) {
if (entry.getKey() == null) continue;
if (Objects.equals(entry.getKey(), sectionKey)) return entry.getValue();
Pattern pattern = Pattern.compile(entry.getKey().replace(".", "\\.").replace("*", "(.*)"));
if (pattern.matcher(sectionKey).matches()) return entry.getValue();
}
return null;
}
public static @Nullable List<String> getHeaderComments(@NotNull ConfigurationHolder<?> holder, @Nullable String path) {
return holder.metadata(path).get(CommentableMeta.HEADER);
}
public static @Nullable List<String> getFooterComments(@NotNull ConfigurationHolder<?> holder, @Nullable String path) {
return holder.metadata(path).get(CommentableMeta.FOOTER);
}
}
@@ -1,4 +1,4 @@
package cc.carm.lib.configuration.option;
package cc.carm.lib.configuration.commentable;
import cc.carm.lib.configuration.source.option.ConfigurationOption;
+1 -1
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId>
<version>4.0.0</version>
<version>4.0.1</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
+1 -1
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId>
<version>4.0.0</version>
<version>4.0.1</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
+60
View File
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId>
<version>4.0.1</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
<maven.compiler.source>${project.jdk.version}</maven.compiler.source>
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties>
<artifactId>easyconfiguration-feature-text</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>easyconfiguration-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>easyconfiguration-yaml</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,196 @@
package cc.carm.lib.configuration.value.text;
import cc.carm.lib.configuration.adapter.ValueAdapter;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.builder.AbstractConfigBuilder;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.value.ValueManifest;
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
import cc.carm.lib.configuration.value.text.data.TextContents;
import cc.carm.lib.configuration.value.text.function.TextDispatcher;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
/**
* @param <MSG> The type of the message
* @param <RECEIVER> The type of the receiver
*/
public class ConfiguredText<MSG, RECEIVER> extends ConfiguredValue<TextContents> {
public static <M, R> Builder<M, R, ?> builder() {
return new StardardBuilder<>();
}
public static final ValueType<TextContents> TEXT_TYPE = ValueType.of(TextContents.class);
public static final ValueAdapter<TextContents> TEXT_ADAPTER = new ValueAdapter<>(TEXT_TYPE,
(h, t, d) -> d.serialize(),
(h, t, d) -> TextContents.deserialize(d)
);
protected final @NotNull BiFunction<RECEIVER, String, String> parser;
protected final @NotNull BiFunction<RECEIVER, String, MSG> compiler;
protected final @NotNull BiConsumer<RECEIVER, List<MSG>> dispatcher;
protected final @NotNull String[] params; // The parameters of the message.
public ConfiguredText(@NotNull ValueManifest<TextContents> manifest,
@NotNull BiFunction<RECEIVER, String, String> parser,
@NotNull BiFunction<RECEIVER, String, MSG> compiler,
@NotNull BiConsumer<RECEIVER, List<MSG>> dispatcher,
@NotNull String[] params) {
super(manifest, TEXT_ADAPTER);
this.parser = parser;
this.compiler = compiler;
this.dispatcher = dispatcher;
this.params = params;
}
public TextDispatcher<MSG, RECEIVER, ?> prepare(@NotNull Object... values) {
return new PreparedText<MSG, RECEIVER>(resolve(), this.params)
.parser(this.parser).compiler(this.compiler)
.dispatcher(this.dispatcher).placeholders(values);
}
/**
* Parse the message for the receiver.
*
* @param receiver The receiver of the message.
* @param values The values to replace the {@link #params}.
* @return The parsed message.
*/
public List<String> parse(@Nullable RECEIVER receiver, @NotNull Object... values) {
return prepare(values).parse(receiver);
}
/**
* Parse the message for the receiver and send it.
*
* @param receiver The receiver of the message.
* @param values The values to replace the {@link #params}.
* @return The parsed message.
*/
public String parseLine(@Nullable RECEIVER receiver, @NotNull Object... values) {
return prepare(values).parseLine(receiver);
}
/**
* Compile the message for the receiver.
*
* @param receiver The receiver of the message.
* @param values The values to replace the {@link #params}.
* @return The compiled message.
*/
public List<MSG> compile(@Nullable RECEIVER receiver, @NotNull Object... values) {
return prepare(values).compile(receiver);
}
/**
* Compile the message for the receiver and send it.
*
* @param receiver The receiver of the message.
* @param values The values to replace the {@link #params}.
* @return The compiled message.
*/
public MSG compileLine(@Nullable RECEIVER receiver, @NotNull Object... values) {
return prepare(values).compileLine(receiver);
}
/**
* Send the message to the receiver.
*
* @param receiver The receiver of the message.
* @param values The values to replace the {@link #params}.
*/
public void sendTo(@NotNull RECEIVER receiver, @NotNull Object... values) {
prepare(values).to(receiver);
}
/**
* Send the message to the multiple receivers.
*
* @param receivers The receivers of the message.
* @param values The values to replace the {@link #params}.
*/
public void sendToAll(@NotNull Iterable<? extends RECEIVER> receivers, @NotNull Object... values) {
prepare(values).to(receivers);
}
public abstract static class Builder<MSG, RECEIVER, SELF extends Builder<MSG, RECEIVER, SELF>>
extends AbstractConfigBuilder<TextContents, ConfiguredText<MSG, RECEIVER>, ConfigurationHolder<?>, SELF> {
protected @NotNull TextContents.Builder defaultBuilder = TextContents.builder();
protected @NotNull String[] params = new String[0];
protected @NotNull BiFunction<RECEIVER, String, String> parser = (r, s) -> s;
protected @NotNull BiFunction<RECEIVER, String, MSG> compiler = (r, s) -> {
throw new IllegalStateException("Compiler not supplied.");
};
protected @NotNull BiConsumer<RECEIVER, List<MSG>> dispatcher = (r, l) -> {
throw new IllegalStateException("Dispatcher not supplied.");
};
protected Builder() {
super(ConfigurationHolder.class, TEXT_TYPE);
defaults(() -> defaultBuilder.build()); // Set the default value from the default builder.
}
public @NotNull SELF parser(@NotNull BiFunction<RECEIVER, String, String> parser) {
this.parser = parser;
return self();
}
public @NotNull SELF compiler(@NotNull BiFunction<RECEIVER, String, MSG> compiler) {
this.compiler = compiler;
return self();
}
public @NotNull SELF dispatcher(@NotNull BiConsumer<RECEIVER, List<MSG>> dispatcher) {
this.dispatcher = dispatcher;
return self();
}
public @NotNull SELF params(@NotNull String... params) {
this.params = params;
return self();
}
public @NotNull SELF defaults(@NotNull Consumer<TextContents.Builder> consumer) {
consumer.accept(this.defaultBuilder);
return self();
}
public @NotNull SELF defaults(@NotNull String... contents) {
return defaults(builder -> builder.set(contents));
}
public @NotNull SELF defaults(@NotNull Iterable<String> contents) {
return defaults(builder -> builder.set(contents));
}
public @NotNull SELF optional(@NotNull String id, @NotNull String... lines) {
return defaults(builder -> builder.optional(id, lines));
}
public @NotNull SELF optional(@NotNull String id, @NotNull Iterable<String> lines) {
return defaults(builder -> builder.optional(id, lines));
}
@Override
public @NotNull ConfiguredText<MSG, RECEIVER> build() {
return new ConfiguredText<>(buildManifest(), this.parser, this.compiler, this.dispatcher, this.params);
}
}
public static class StardardBuilder<MSG, RECEIVER> extends Builder<MSG, RECEIVER, StardardBuilder<MSG, RECEIVER>> {
@Override
protected @NotNull StardardBuilder<MSG, RECEIVER> self() {
return this;
}
}
}
@@ -0,0 +1,32 @@
package cc.carm.lib.configuration.value.text;
import cc.carm.lib.configuration.value.text.data.TextContents;
import cc.carm.lib.configuration.value.text.function.TextDispatcher;
import org.jetbrains.annotations.NotNull;
public class PreparedText<MSG, RECEIVER> extends TextDispatcher<MSG, RECEIVER, PreparedText<MSG, RECEIVER>> {
protected final @NotNull TextContents texts;
public PreparedText(@NotNull TextContents texts, @NotNull String... params) {
this.params = params;
this.texts = texts;
}
@Override
public TextContents texts() {
return this.texts;
}
@Override
public PreparedText<MSG, RECEIVER> self() {
return this;
}
public PreparedText<MSG, RECEIVER> insert(@NotNull String key,
@NotNull ConfiguredText<?, RECEIVER> message,
@NotNull Object... values) {
return insert(key, receiver -> message.parse(receiver, values));
}
}
@@ -0,0 +1,160 @@
package cc.carm.lib.configuration.value.text.data;
import cc.carm.lib.configuration.source.section.ConfigureSection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
public class TextContents {
public static Builder builder() {
return new Builder();
}
public static TextContents of(@NotNull List<String> lines, @NotNull Map<String, List<String>> optional) {
return new TextContents(lines, optional);
}
protected final @NotNull List<String> lines;
protected final @NotNull Map<String, List<String>> optional;
public TextContents(@NotNull List<String> lines, @NotNull Map<String, List<String>> optional) {
this.lines = lines;
this.optional = optional;
}
public boolean isEmpty() {
return lines.isEmpty() || lines.stream().allMatch(String::isEmpty);
}
public @NotNull List<String> lines() {
return lines;
}
public @NotNull Map<String, List<String>> optionalLines() {
return optional;
}
public @Nullable Object serialize() {
if (optional.isEmpty()) {
if (lines.isEmpty()) return null;
else if (lines.size() == 1) return lines.get(0);
else return lines;
} else {
Map<String, Object> map = new LinkedHashMap<>();
map.put("contents", lines);
map.put("optional", optional);
return map;
}
}
public static @Nullable TextContents deserialize(@NotNull Object data) {
Builder builder = builder();
if (data instanceof String) {
return builder.set((String) data).build();
} else if (data instanceof List<?>) {
((List<?>) data).stream().map(Object::toString).forEach(builder::add);
return builder.build();
} else if (data instanceof ConfigureSection) {
ConfigureSection section = (ConfigureSection) data;
builder.set(section.getStringList("contents"));
ConfigureSection optionalSection = section.getSection("optional");
if (optionalSection != null) {
for (String key : optionalSection.getKeys(false)) {
builder.optional(key, optionalSection.getStringList(key));
}
}
return builder.build();
}
return null;
}
public static class Builder {
protected List<String> lines = new ArrayList<>();
protected Map<String, List<String>> optional = new HashMap<>();
/**
* Add lines to the contents
*
* @param lines lines to add
* @return this builder
*/
public Builder add(@NotNull String... lines) {
this.lines.addAll(Arrays.asList(lines));
return this;
}
/**
* Add lines to the contents
*
* @param lines lines to add
* @return this builder
*/
public Builder add(@NotNull Iterable<String> lines) {
lines.forEach(this.lines::add);
return this;
}
/**
* Set the lines of the contents
*
* @param lines lines to set
* @return this builder
*/
public Builder set(@NotNull String... lines) {
this.lines = Arrays.asList(lines);
return this;
}
/**
* Set the lines of the contents
*
* @param lines lines to set
* @return this builder
*/
public Builder set(@NotNull Iterable<String> lines) {
this.lines = new ArrayList<>();
lines.forEach(this.lines::add);
return this;
}
/**
* Add optional lines to the contents
*
* @param key key of the optional lines
* @param lines lines to add
* @return this builder
*/
public Builder optional(@NotNull String key, @NotNull String... lines) {
optional.put(key, Arrays.asList(lines));
return this;
}
/**
* Add optional lines to the contents
*
* @param key key of the optional lines
* @param lines lines to add
* @return this builder
*/
public Builder optional(@NotNull String key, @NotNull Iterable<String> lines) {
List<String> list = new ArrayList<>();
lines.forEach(list::add);
optional.put(key, list);
return this;
}
/**
* @return The built TextContents
*/
public TextContents build() {
return of(lines, optional);
}
}
}
@@ -0,0 +1,259 @@
package cc.carm.lib.configuration.value.text.function;
import cc.carm.lib.configuration.value.text.data.TextContents;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.UnaryOperator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.IntStream;
public abstract class ContentHandler<RECEIVER, SELF extends ContentHandler<RECEIVER, SELF>> {
/**
* Used to match the message insertion
* <p>
* format:
* <br>- to insert parsed line {prefix}#content-id#{offset-above,offset-down}
* <br>- to insert original line {prefix}@content-id@{offset-above,offset-down}
* <br> example:
* <ul>
* <li>{- }#content-id#{1,1}</li>
* <li>@content-id@{1,1}</li>
* </ul>
*/
public static final @NotNull Pattern INSERT_PATTERN = Pattern.compile(
"^(?:\\{(?<prefix>.*)})?(?<type>[#@])(?<id>.*)[#@](?:\\{(?<above>-?\\d+)(?:,(?<down>-?\\d+))?})?$"
);
public static final @NotNull UnaryOperator<String> DEFAULT_PARAM_BUILDER = s -> "%(" + s + ")";
protected BiFunction<RECEIVER, String, String> parser = (receiver, value) -> value;
protected String lineSeparator = System.lineSeparator();
/**
* Used to store the placeholders of the message
*/
protected @NotNull Map<String, Object> placeholders = new HashMap<>();
protected @NotNull UnaryOperator<String> paramFormatter = DEFAULT_PARAM_BUILDER;
protected @NotNull String[] params;
/**
* Used to store the insertion of the message
*/
protected @NotNull Map<String, Function<RECEIVER, List<String>>> insertion = new HashMap<>();
protected boolean disableInsertion = false;
public abstract SELF self();
/**
* Disable the insertion of the text.
* <br> If the insertion is disabled, the text will be parsed directly.
*
* @return the current {@link ContentHandler} instance
*/
public SELF disableInsertion() {
this.disableInsertion = true;
return self();
}
/**
* Enable the insertion of the text.
*
* @return the current {@link ContentHandler} instance
*/
public SELF enableInsertion() {
this.disableInsertion = false;
return self();
}
/**
* Set the line separator for the text.
*
* @param lineSeparator the line separator, default is {@link System#lineSeparator()}
* @return the current {@link ContentHandler} instance
*/
public SELF lineSeparator(@NotNull String lineSeparator) {
this.lineSeparator = lineSeparator;
return self();
}
/**
* Set all the placeholders for the text.
* <br> Will override the previous placeholders modifications.
*
* @param placeholders the placeholders
* @return the current {@link ContentHandler} instance
*/
public SELF placeholders(@NotNull Map<String, Object> placeholders) {
this.placeholders = placeholders;
return self();
}
/**
* Set the placeholders for the text.
*
* @param consumer the placeholders
* @return the current {@link ContentHandler} instance
*/
public SELF placeholders(@NotNull Consumer<Map<String, Object>> consumer) {
consumer.accept(this.placeholders);
return self();
}
/**
* Set the placeholders for the text.
*
* @param values The values to replace the {@link #params(String...)}.
* @return the current {@link ContentHandler} instance
*/
public SELF placeholders(@Nullable Object... values) {
return placeholders(map -> map.putAll(buildParams(this.paramFormatter, this.params, values)));
}
/**
* Set the placeholder for the text.
*
* @param key the key of the placeholder
* @param value the value of the placeholder
* @return the current {@link ContentHandler} instance
*/
public SELF placeholder(@NotNull String key, @Nullable Object value) {
this.placeholders.put(paramFormatter.apply(key), value);
return self();
}
/**
* Set the params for the text,
* used for {@link #placeholders(Object...)} to build the placeholders.
*
* @param params the params
* @return the current {@link ContentHandler} instance
*/
public SELF params(@NotNull String... params) {
this.params = params;
return self();
}
/**
* Insert the specific contents by the id.
*
* @param id the id of the insertion text
* @param linesSupplier to supply the lines to insert
* @return the current {@link ContentHandler} instance
*/
public SELF insert(@NotNull String id, @NotNull Function<RECEIVER, List<String>> linesSupplier) {
this.insertion.put(id, linesSupplier);
return self();
}
/**
* Insert the specific contents by the id.
*
* @param id the id of the insertion text
* @param lines the lines to insert
* @return the current {@link ContentHandler} instance
*/
public SELF insert(@NotNull String id, @NotNull String... lines) {
return insert(id, Arrays.asList(lines));
}
/**
* Insert the specific contents by the id.
*
* @param id the id of the insertion text
* @param lines the lines to insert
* @return the current {@link ContentHandler} instance
*/
public SELF insert(@NotNull String id, @NotNull List<String> lines) {
return insert(id, receiver -> lines);
}
/**
* Set the parser for the text.
*
* @param parser The parser
* @return The current {@link ContentHandler} instance
*/
public SELF parser(@NotNull BiFunction<RECEIVER, String, String> parser) {
this.parser = parser;
return self();
}
/**
* Parse the supplied single text for the receiver.
*
* @param receiver the receiver
* @param text the text to parse
* @return the parsed text
*/
protected @Nullable String parse(@Nullable RECEIVER receiver, @NotNull String text) {
return this.parser.apply(receiver, setPlaceholders(text, this.placeholders));
}
public void handle(@NotNull TextContents contents, @Nullable RECEIVER receiver,
@NotNull Consumer<String> lineConsumer) {
if (contents.isEmpty()) return; // Nothing to parse
if (this.disableInsertion) {
contents.lines().forEach(line -> lineConsumer.accept(parse(receiver, line)));
return; // Simple parsed
}
for (String line : contents.lines()) {
Matcher matcher = INSERT_PATTERN.matcher(line);
if (!matcher.matches()) {
lineConsumer.accept(parse(receiver, line));
continue;
}
String id = matcher.group("id");
List<String> values = Optional.ofNullable(this.insertion.get(id))
.map(f -> f.apply(receiver))
.orElse(null);
if (values == null || values.isEmpty()) continue;
String prefix = matcher.group("prefix");
String type = matcher.group("type");
boolean original = type.equals("@");
int offsetAbove = Optional.ofNullable(matcher.group("above"))
.map(Integer::parseInt).orElse(0);
int offsetDown = Optional.ofNullable(matcher.group("down"))
.map(Integer::parseInt).orElse(offsetAbove); // If offsetDown is not set, use offsetAbove
IntStream.range(0, Math.max(0, offsetAbove)).mapToObj(i -> "").forEach(lineConsumer);
String prefixContent = Optional.ofNullable(prefix).map(p -> parse(receiver, p)).orElse("");
if (original) {
values.stream().map(value -> prefixContent + value).forEach(lineConsumer);
} else {
values.stream().map(value -> prefixContent + parse(receiver, value)).forEach(lineConsumer);
}
IntStream.range(0, Math.max(0, offsetDown)).mapToObj(i -> "").forEach(lineConsumer);
}
}
public static String setPlaceholders(@NotNull String messages,
@NotNull Map<String, Object> placeholders) {
if (messages.isEmpty()) return messages;
String parsed = messages;
for (Map.Entry<String, Object> entry : placeholders.entrySet()) {
parsed = parsed.replace(entry.getKey(), entry.getValue() == null ? "" : entry.getValue().toString());
}
return parsed;
}
public static Map<String, Object> buildParams(@NotNull UnaryOperator<String> paramBuilder,
@Nullable String[] params, @Nullable Object[] values) {
Map<String, Object> map = new HashMap<>();
if (params == null || params.length == 0) return map;
for (int i = 0; i < params.length; i++) {
map.put(paramBuilder.apply(params[i]), (values != null && values.length > i) ? values[i] : "?");
}
return map;
}
}
@@ -0,0 +1,45 @@
package cc.carm.lib.configuration.value.text.function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.function.BiFunction;
public abstract class TextCompiler<MSG, RECEIVER, SELF extends TextCompiler<MSG, RECEIVER, SELF>> extends TextParser<RECEIVER, SELF> {
protected BiFunction<RECEIVER, String, MSG> compiler = (receiver, value) -> null;
/**
* Set the text compiler.
*
* @param compiler The text compiler.
* @return The current {@link TextCompiler} instance.
*/
public SELF compiler(@NotNull BiFunction<RECEIVER, String, MSG> compiler) {
this.compiler = compiler;
return self();
}
/**
* Compile the text for specific receiver.
*
* @param receiver The receiver.
* @return The compiled text.
* @see #parse(Object, BiFunction)
*/
public @NotNull List<MSG> compile(@Nullable RECEIVER receiver) {
return parse(receiver, this.compiler);
}
/**
* Compile the singleton text for specific receiver.
*
* @param receiver The receiver.
* @return The compiled text.
* @see #parseLine(Object, BiFunction)
*/
public @Nullable MSG compileLine(@Nullable RECEIVER receiver) {
return parseLine(receiver, this.compiler);
}
}
@@ -0,0 +1,61 @@
package cc.carm.lib.configuration.value.text.function;
import cc.carm.lib.configuration.value.text.data.TextContents;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
public abstract class TextDispatcher<MSG, RECEIVER, SELF extends TextDispatcher<MSG, RECEIVER, SELF>> extends TextCompiler<MSG, RECEIVER, SELF> {
protected @NotNull BiConsumer<RECEIVER, List<MSG>> dispatcher = (receiver, msg) -> {
};
/**
* Set the dispatcher to send the message to the receiver
*
* @param dispatcher the dispatcher
* @return {@link TextDispatcher}
*/
public SELF dispatcher(@NotNull BiConsumer<RECEIVER, List<MSG>> dispatcher) {
this.dispatcher = dispatcher;
return self();
}
/**
* Dispatch the message to the receiver
*
* @param receivers the receivers
*/
@SafeVarargs
public final void to(@NotNull RECEIVER... receivers) {
if (receivers.length == 0) return;
to(Arrays.asList(receivers));
}
/**
* Dispatch the message to the receiver
*
* @param receivers the receivers
*/
public void to(@NotNull Iterable<? extends RECEIVER> receivers) {
for (RECEIVER receiver : receivers) {
List<MSG> msg = compile(receiver);
if (msg.isEmpty()) return;
dispatcher.accept(receiver, msg);
}
}
/**
* Dispatch the message to the receiver
*
* @param receivers the receivers
*/
public void to(@NotNull Supplier<Iterable<? extends RECEIVER>> receivers) {
to(receivers.get());
}
}
@@ -0,0 +1,74 @@
package cc.carm.lib.configuration.value.text.function;
import cc.carm.lib.configuration.value.text.data.TextContents;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Consumer;
public abstract class TextParser<RECEIVER, SELF extends TextParser<RECEIVER, SELF>>
extends ContentHandler<RECEIVER, SELF> {
public abstract TextContents texts();
/**
* Parse the texts for the receiver.
*
* @param receiver the receiver
* @return the parsed line
*/
public List<String> parse(@Nullable RECEIVER receiver) {
List<String> result = new ArrayList<>();
handle(receiver, result::add);
return result;
}
/**
* Parse the texts for the receiver.
*
* @param receiver the receiver
* @param compiler the compiler
* @param <V> the type of the message
* @return the parsed line
*/
public <V> List<V> parse(@Nullable RECEIVER receiver, @NotNull BiFunction<RECEIVER, String, V> compiler) {
List<V> result = new ArrayList<>();
handle(receiver, s -> result.add(compiler.apply(receiver, s)));
return result;
}
/**
* Parse the texts as a single line for the receiver.
*
* @param receiver the receiver
* @return the parsed line
*/
public @Nullable String parseLine(@Nullable RECEIVER receiver) {
if (texts().isEmpty()) return null;
StringBuilder builder = new StringBuilder();
handle(receiver, s -> builder.append(s).append(this.lineSeparator));
// Remove the last line separator, if it exists
if (builder.length() > 0) builder.delete(builder.length() - this.lineSeparator.length(), builder.length());
return builder.toString();
}
/**
* Parse the texts as a single line for the receiver.
*
* @param receiver the receiver
* @param <V> the type of the message
* @return the parsed line
*/
public <V> @Nullable V parseLine(@Nullable RECEIVER receiver, @NotNull BiFunction<RECEIVER, String, V> compiler) {
return Optional.ofNullable(parseLine(receiver)).map(s -> compiler.apply(receiver, s)).orElse(null);
}
public void handle(@Nullable RECEIVER receiver, @NotNull Consumer<String> lineConsumer) {
handle(texts(), receiver, lineConsumer);
}
}
@@ -0,0 +1,47 @@
package cc.carm.lib.configuration.value.text.tests;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.yaml.YAMLConfigFactory;
import cc.carm.lib.configuration.value.text.tests.conf.AppMessages;
import org.junit.Test;
public class ConfigTest {
public static final String[] WEBSITES = new String[]{
"https://carm.cc",
"https://www.baidu.com",
"https://www.google.com"
};
@Test
public void test() {
ConfigurationHolder<?> holder = YAMLConfigFactory.from("target/messages.yml").build();
holder.initialize(AppMessages.class);
System.out.println("--------------------------");
AppMessages.WELCOME.prepare()
.placeholders("Carm")
.insert("guidance")
.insert("websites", WEBSITES)
.to(System.out);
System.out.println("--------------------------");
AppMessages.NOT_AVAILABLE.sendTo(System.out);
System.out.println("--------------------------");
AppMessages.NO_PERMISSION.sendTo(System.out);
System.out.println("--------------------------");
}
}
@@ -0,0 +1,49 @@
package cc.carm.lib.configuration.value.text.tests;
import cc.carm.lib.configuration.value.text.PreparedText;
import cc.carm.lib.configuration.value.text.data.TextContents;
import org.junit.Test;
import java.io.PrintStream;
import java.util.*;
public class ParseTest {
@Test
public void test() {
List<String> lines = new ArrayList<>();
lines.add("Hello, %(name)");
lines.add("#more-creating#{1}");
lines.add("This is a test message");
lines.add("#guidance#");
lines.add("{- }#websites#{0,1}");
lines.add("Thanks for your reading!");
Map<String, List<String>> optional = new HashMap<>();
optional.put("guidance", Arrays.asList("To get more information for %(name), see:"));
optional.put("websites", Arrays.asList("https://www.baidu.com", "https://www.google.com"));
TextContents textContents = new TextContents(lines, optional);
PreparedText<String, PrintStream> msg = new PreparedText<String, PrintStream>(textContents)
.dispatcher((p, s) -> s.forEach(p::println))
.parser((p, s) -> s)
.compiler((p, s) -> s);
msg.placeholder("name", "Carm")
.insert("guidance")
.insert("websites", "Baidu", "Bilibili", "Google");
System.out.println("----------------------------");
msg.to(System.out);
System.out.println("----------------------------");
System.out.println(msg.compileLine(System.out));
System.out.println("----------------------------");
}
}
@@ -0,0 +1,28 @@
package cc.carm.lib.configuration.value.text.tests.conf;
import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.annotation.ConfigPath;
@ConfigPath(root = true)
public interface AppMessages extends Configuration {
ConfiguredMsg WELCOME = ConfiguredMsg.builder()
.defaults(
"Hello, %(name)",
"#more-creating#{1}",
"This is a test message",
"#guidance#",
"{- }#websites#{0,1}",
"Thanks for your reading!")
.optional("guidance", "To get more information for %(name), see:")
.params("name").build();
ConfiguredMsg NO_PERMISSION = ConfiguredMsg.builder()
.defaults("Sorry! But you don't have permissions to do this.")
.build();
ConfiguredMsg NOT_AVAILABLE = ConfiguredMsg.builder()
.defaults("Error! Service is not available now.", "Please contact your system manager.")
.build();
}
@@ -0,0 +1,47 @@
package cc.carm.lib.configuration.value.text.tests.conf;
import cc.carm.lib.configuration.value.ValueManifest;
import cc.carm.lib.configuration.value.text.ConfiguredText;
import cc.carm.lib.configuration.value.text.data.TextContents;
import org.jetbrains.annotations.NotNull;
import java.io.PrintStream;
public class ConfiguredMsg extends ConfiguredText<String, PrintStream> {
public static @NotNull MsgBuilder builder() {
return new MsgBuilder();
}
public static @NotNull ConfiguredMsg of(@NotNull String... text) {
return builder().defaults(text).build();
}
public ConfiguredMsg(@NotNull ValueManifest<TextContents> manifest, @NotNull String[] params) {
super(
manifest,
(p, s) -> s,
(p, s) -> s,
(p, s) -> s.forEach(p::println),
params
);
}
public void print(@NotNull Object... values) {
sendTo(System.out, values);
}
public static class MsgBuilder extends Builder<String, PrintStream, MsgBuilder> {
@Override
protected @NotNull MsgBuilder self() {
return this;
}
@Override
public @NotNull ConfiguredMsg build() {
return new ConfiguredMsg(buildManifest(), params);
}
}
}
+1 -1
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId>
<version>4.0.0</version>
<version>4.0.1</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
+2 -1
View File
@@ -15,13 +15,14 @@
<groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId>
<packaging>pom</packaging>
<version>4.0.0</version>
<version>4.0.1</version>
<modules>
<module>core</module>
<module>features/section</module>
<module>features/file</module>
<module>features/commentable</module>
<module>features/versioned</module>
<module>features/text</module>
<module>providers/yaml</module>
<module>providers/gson</module>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>easyconfiguration-parent</artifactId>
<groupId>cc.carm.lib</groupId>
<version>4.0.0</version>
<version>4.0.1</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+3 -3
View File
@@ -6,7 +6,7 @@
<parent>
<artifactId>easyconfiguration-parent</artifactId>
<groupId>cc.carm.lib</groupId>
<version>4.0.0</version>
<version>4.0.1</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
@@ -14,7 +14,7 @@
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<deps.yamlcommentwriter.version>1.1.0</deps.yamlcommentwriter.version>
<deps.yamlcommentwriter.version>1.2.0</deps.yamlcommentwriter.version>
</properties>
<artifactId>easyconfiguration-yaml</artifactId>
@@ -32,7 +32,7 @@
<dependency>
<groupId>cc.carm.lib</groupId>
<artifactId>yamlcommentwriter</artifactId>
<version>1.1.0</version>
<version>1.2.0</version>
<scope>compile</scope>
</dependency>
@@ -1,5 +1,6 @@
package cc.carm.lib.configuration.source.yaml;
import cc.carm.lib.configuration.commentable.Commentable;
import cc.carm.lib.configuration.commentable.CommentableMeta;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.file.FileConfigFactory;
@@ -125,7 +126,7 @@ public class YAMLConfigFactory extends FileConfigFactory<YAMLSource, Configurati
File configFile = this.file;
String sourcePath = this.resourcePath;
CommentableMeta.register(this.initializer); // Register commentable meta types
Commentable.registerMeta(this.initializer); // Register commentable meta types
return new ConfigurationHolder<YAMLSource>(this.adapters, this.options, this.metadata, this.initializer) {
final @NotNull YAMLSource source = new YAMLSource(this, configFile, sourcePath);
@@ -1,7 +1,7 @@
package cc.carm.lib.configuration.source.yaml;
import cc.carm.lib.configuration.commentable.CommentableMeta;
import cc.carm.lib.configuration.option.CommentableOptions;
import cc.carm.lib.configuration.commentable.Commentable;
import cc.carm.lib.configuration.commentable.CommentableOptions;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.file.FileConfigSource;
import cc.carm.lib.configuration.source.option.StandardOptions;
@@ -25,9 +25,10 @@ import java.io.Reader;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Pattern;
public class YAMLSource extends FileConfigSource<MemorySection, Map<String, Object>, YAMLSource> implements CommentedSection {
public class YAMLSource
extends FileConfigSource<MemorySection, Map<String, Object>, YAMLSource>
implements CommentedSection {
protected final @NotNull YamlConstructor yamlConstructor;
protected final @NotNull YamlRepresenter yamlRepresenter;
@@ -193,46 +194,17 @@ public class YAMLSource extends FileConfigSource<MemorySection, Map<String, Obje
@Override
public @Nullable String getInlineComment(@NotNull String key) {
String comment = getInlineComment(key, null);
if (comment != null) return comment;
String sep = String.valueOf(separator());
// If the comment is not found, try to get the comment from the parent section
String[] keys = key.split(sep);
if (keys.length == 1) return null;
// Try every possible parent key&child key combination
for (int i = 1; i < keys.length; i++) {
String parentKey = String.join(sep, Arrays.copyOfRange(keys, 0, i));
String childKey = String.join(sep, Arrays.copyOfRange(keys, i, keys.length));
comment = getInlineComment(childKey, parentKey);
if (comment != null) return comment;
}
return null;
}
public @Nullable String getInlineComment(@NotNull String key, @Nullable String sectionKey) {
Map<String, String> pathComment = holder().metadata(key).get(CommentableMeta.INLINE);
if (pathComment == null || pathComment.isEmpty()) return null;
if (sectionKey == null) return pathComment.get(null);
for (Map.Entry<String, String> entry : pathComment.entrySet()) {
if (entry.getKey().equals(sectionKey)) return entry.getValue();
Pattern pattern = Pattern.compile(entry.getKey().replace(".", "\\.").replace("*", ".*"));
if (pattern.matcher(sectionKey).matches()) return entry.getValue();
}
return null;
return Commentable.getInlineComment(holder(), key);
}
@Override
public @Nullable List<String> getHeaderComments(@Nullable String key) {
return holder().metadata(key).get(CommentableMeta.HEADER);
return Commentable.getHeaderComments(holder(), key);
}
@Override
public @Nullable List<String> getFooterComments(@Nullable String key) {
return holder().metadata(key).get(CommentableMeta.FOOTER);
return Commentable.getFooterComments(holder(), key);
}
public static class YamlRepresenter extends Representer {
@@ -4,7 +4,7 @@ import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.yaml.YAMLConfigFactory;
import org.junit.Test;
public class SampleTest {
public class SampleTest {
@Test
public void test() {
@@ -4,17 +4,19 @@ import cc.carm.lib.configuration.commentable.CommentableMeta;
import cc.carm.lib.configuration.demo.tests.ConfigurationTest;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.yaml.YAMLConfigFactory;
import cc.carm.lib.configuration.source.yaml.YAMLSource;
import org.junit.Test;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
public class YamlTests {
@Test
public void test() {
ConfigurationHolder<?> holder = YAMLConfigFactory.from("target/tests.yml")
ConfigurationHolder<YAMLSource> holder = YAMLConfigFactory.from("target/tests.yml")
.resourcePath("configs/sample.yml").build();
ConfigurationTest.testDemo(holder);