Skip to content

Commit

Permalink
Refactor Parameters escaping and equality
Browse files Browse the repository at this point in the history
  • Loading branch information
imDaniX committed Feb 21, 2024
1 parent 59cc02c commit e5d2c26
Show file tree
Hide file tree
Showing 10 changed files with 146 additions and 88 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ public void saveOptions(@NotNull ConfigurationSection cfg) {
@Override
public String toString() {
String sb = super.toString() + " (" +
"itemnew:" + (virtualItemNew == VirtualItem.EMPTY ? "-" : virtualItemNew) +
" itemprev:" + (virtualItemPrev == VirtualItem.EMPTY ? "-" : virtualItemPrev) +
"itemnew:" + (virtualItemNew == VirtualItem.ANY ? "-" : virtualItemNew) +
" itemprev:" + (virtualItemPrev == VirtualItem.ANY ? "-" : virtualItemPrev) +
" slotnew:" + (slotNew + 1) +
" slotprev:" + (slotPrev + 1) +
")";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@ private String parseGradually(@NotNull Environment env, @NotNull String text) {
String substring = text.substring(stepIndex + 2, index);
String processed = resolvePlaceholder(env, substring);
if (processed != null) {
if (text.length() > index + 3 && text.charAt(index + 1) == '(') {
if (text.length() > index + 3 && text.charAt(index + 1) == '(') { // TODO Better escaping trigger
String options = optionsSearch(text, index + 2);
if (options != null) {
index += options.length() + 2;
if (options.contains("prms")) processed = Parameters.escapeParameters(processed);
if (options.contains("prms")) processed = Parameters.escapeValue(processed);
if (options.contains("phs")) processed = escapeSpecial(processed);
}
}
Expand Down
51 changes: 33 additions & 18 deletions reactions/src/main/java/fun/reactions/util/item/VirtualItem.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package fun.reactions.util.item;

import fun.reactions.util.Utils;
import fun.reactions.util.item.aspects.*;
import fun.reactions.util.naming.Aliased;
import fun.reactions.util.num.NumberUtils;
Expand All @@ -19,7 +18,7 @@
import java.util.stream.Collectors;

public final class VirtualItem implements Parameterizable {
private static final Pattern SIMPLE_ITEM = Pattern.compile("([a-zA-Z_]+)(?::(\\d+))?(?:\\*(\\d+))?");
private static final Pattern SIMPLE_ITEM = Pattern.compile("([a-zA-Z\\d_]+)(?::(\\d{1,9}))?(?:\\*(\\d{1,9}))?");

/**
* A VirtualItem that accepts only null or air ItemStacks
Expand All @@ -28,9 +27,9 @@ public final class VirtualItem implements Parameterizable {
/**
* A VirtualItem that accepts any ItemStacks but null or air
*/
public static final VirtualItem EMPTY = new VirtualItem(null, -1, List.of(), Parameters.EMPTY);
public static final VirtualItem ANY = new VirtualItem(null, -1, List.of(), Parameters.EMPTY);
/**
* A VirtualItem that accepts noting
* A VirtualItem that accepts nothing
*/
public static final VirtualItem INVALID = new VirtualItem(null, -1, List.of(new MetaAspect.Instance() {
@Override
Expand Down Expand Up @@ -181,18 +180,21 @@ public int getAmount() {
? null
: itemValue.clone();
} else {
itemGenerated = true;
if (type == null || !type.isItem()) {
return null;
} else {
itemValue = new ItemStack(type);
itemValue.setAmount(Math.max(amount, 1));
if (!type.isEmpty() && !aspects.isEmpty()) {
ItemMeta meta = itemValue.getItemMeta();
aspects.forEach(aspect -> aspect.apply(meta));
itemValue.setItemMeta(meta);
ItemStack genItem = new ItemStack(type);
if (!type.isEmpty()) {
genItem.setAmount(Math.max(amount, 1));
if (!aspects.isEmpty()) {
ItemMeta meta = genItem.getItemMeta();
aspects.forEach(aspect -> aspect.apply(meta));
genItem.setItemMeta(meta);
}
}
return initClone ? itemValue.clone() : itemValue;
itemValue = genItem;
itemGenerated = true;
return initClone ? genItem.clone() : genItem;
}
}
}
Expand Down Expand Up @@ -304,7 +306,7 @@ public boolean isSimilar(@Nullable ItemStack compared, AmountCheck amountCheck)

@Contract(pure = true)
public static @NotNull VirtualItem fromParameters(@NotNull Parameters params) {
if (params.isEmpty()) return VirtualItem.EMPTY;
if (params.isEmpty()) return VirtualItem.ANY;
List<MetaAspect.Instance> aspects = new ArrayList<>();
Material type = null;
int amount = -1;
Expand All @@ -327,10 +329,10 @@ public boolean isSimilar(@Nullable ItemStack compared, AmountCheck amountCheck)
if (!matcher.matches()) break;
type = ItemUtils.getMaterial(matcher.group(1));
if (type == null) return VirtualItem.INVALID;
if (!Utils.isStringEmpty(matcher.group(2))) {
if (matcher.group(2) != null) {
aspects.add(ASPECTS_BY_NAME.get("durability").fromString(matcher.group(1)));
}
if (!Utils.isStringEmpty(matcher.group(3))) {
if (matcher.group(3) != null) {
amount = NumberUtils.asInteger(matcher.group(3), -1);
}
break;
Expand Down Expand Up @@ -361,15 +363,15 @@ public boolean isSimilar(@Nullable ItemStack compared, AmountCheck amountCheck)
);
}

@Contract("null -> null")
@Contract("null -> null; !null -> !null")
public static @Nullable ItemStack asCleanItemStack(@Nullable ItemStack item) {
if (item == null) return null;
VirtualItem virtual = fromItemStack(item, false);
return new VirtualItem(
virtual.type,
virtual.amount,
virtual.aspects,
virtual.paramsValue
virtual.asParameters()
).asItemStack(false);
}

Expand Down Expand Up @@ -402,6 +404,19 @@ public String toString() {
return asString();
}

@Override
public boolean equals(Object other) {
return this == other || other instanceof VirtualItem otherItem &&
amount == otherItem.amount &&
type == otherItem.type &&
aspects.equals(otherItem.aspects);
}

@Override
public int hashCode() {
return Objects.hash(type, amount, aspects);
}

public enum AmountCheck {
/**
* Skip amount check as a whole
Expand All @@ -412,7 +427,7 @@ public enum AmountCheck {
*/
EQUAL,
/**
* Checks if amount of ItemStack satisfies amount of VirtualItem
* Checks if amount of ItemStack satisfies (>=) amount of VirtualItem
*/
SATISFIES
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public void apply(@NotNull ItemMeta meta) {
@Override
public boolean isSimilar(@NotNull ItemMeta meta) {
if (meta instanceof Damageable damageMeta) {
return value < 0 ? !damageMeta.hasDamage() : damageMeta.getDamage() >= value;
return value >= 0 ? damageMeta.getDamage() >= value : !damageMeta.hasDamage();
}
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class EnchantmentsAspect implements MetaAspect {
}

@Override
public @NotNull EnchantmentsAspect.EnchantmentsInst fromString(@NotNull String value) {
public @NotNull MetaAspect.Instance fromString(@NotNull String value) {
if (value.isEmpty()) {
return EnchantmentsInst.EMPTY;
}
Expand Down Expand Up @@ -53,7 +53,7 @@ public class EnchantmentsAspect implements MetaAspect {
}

@Override
public EnchantmentsInst fromItem(@NotNull ItemMeta meta) {
public MetaAspect.Instance fromItem(@NotNull ItemMeta meta) {
Map<Enchantment, Integer> enchants = meta instanceof EnchantmentStorageMeta enchantmentMeta
? enchantmentMeta.getStoredEnchants()
: meta.getEnchants();
Expand Down
15 changes: 0 additions & 15 deletions reactions/src/main/java/fun/reactions/util/num/Is.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,6 @@
public final class Is {
private Is() {}

/**
* Checks if number is an integer (has no floating value)
*/
public static final DoublePredicate INTEGER = v -> v == (long) v;

/**
* Checks if number is positive
*/
Expand All @@ -23,7 +18,6 @@ private Is() {}
* Check if number is positive or zero
*/
public static final DoublePredicate NON_NEGATIVE = v -> v >= 0;

/**
* Checks if number is negative
*/
Expand All @@ -33,15 +27,6 @@ private Is() {}
*/
public static final DoublePredicate NON_POSITIVE = v -> v <= 0;

/**
* Checks if number is positive and integer
*/
public static final DoublePredicate POSITIVE_NATURAL = POSITIVE.and(INTEGER);
/**
* Checks if number is positive or zero and integer
*/
public static final DoublePredicate NATURAL = NON_NEGATIVE.and(INTEGER);

public static @NotNull DoublePredicate inRange(double min, double max) {
return v -> min <= v && v < max;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,13 @@
import java.util.function.*;
import java.util.regex.Pattern;

import static ink.glowing.text.InkyMessage.isEscapedAt;

public class Parameters implements Parameterizable {
public static final String ORIGIN = " :";
public static final String ORIGIN = ": ";
public static final Parameters EMPTY = new Parameters("", "", new CaseInsensitiveMap<>(1));
private static final Pattern UNESCAPED = Pattern.compile("(?<!\\\\)[{}]");
private static final Pattern VALUE_ESCAPE = Pattern.compile("(?<!\\\\)[{}]");
private static final Pattern FULL_ESCAPE = Pattern.compile("[{}:\\\\]");

private final String origin;
private final Map<String, String> params;
Expand All @@ -44,6 +47,10 @@ protected Parameters(@NotNull String origin, @NotNull String formatted, @NotNull
this.formatted = formatted;
}

public static @NotNull String originKey() {
return ORIGIN;
}

public static @NotNull Parameters fromConfiguration(@NotNull ConfigurationSection cfg) {
return fromConfiguration(cfg, Set.of());
}
Expand Down Expand Up @@ -104,7 +111,7 @@ protected Parameters(@NotNull String origin, @NotNull String formatted, @NotNull
int next = i + 1;
if (next < str.length()) {
char n = str.charAt(next);
if (n == '{' || n == '}' || (n == '\\' && next + 1 < str.length() && str.charAt(next + 1) == '}')) {
if ("{}:\\".indexOf(n) != -1) {
if (state == IterationState.SPACE) {
bld = new StringBuilder();
state = IterationState.TEXT;
Expand Down Expand Up @@ -195,7 +202,7 @@ private enum IterationState {
public static @NotNull Parameters singleton(@NotNull String key, @NotNull String value) {
Map<String, String> params = new CaseInsensitiveMap<>(2);
params.put(key, value);
String escaped = escapeParameters(value);
String escaped = escapeValue(value);
String origin;
if (requiresBrackets(escaped, value)) {
origin = key + ":{" + escaped + "}";
Expand All @@ -210,7 +217,7 @@ private enum IterationState {
map.forEach((key, value) -> {
if (key.equals(ORIGIN)) return;
bld.append(key).append(':');
String escaped = escapeParameters(value);
String escaped = escapeValue(value);
if (requiresBrackets(escaped, value)) {
bld.append('{').append(escaped).append('}');
} else {
Expand All @@ -226,7 +233,7 @@ public static boolean requiresBrackets(@NotNull String escaped, @NotNull String
value.indexOf(' ') != -1 || value.indexOf(':') != -1 || value.charAt(0) == '{';
}

public static @NotNull String escapeParameters(@NotNull String str) {
public static @NotNull String escapeValue(@NotNull String str) {
if (str.isEmpty()) return str;
int brackets = 0;
boolean escaped = false;
Expand All @@ -244,14 +251,19 @@ public static boolean requiresBrackets(@NotNull String escaped, @NotNull String
break;
}
}
if (str.charAt(str.length() - 1) == '\\' && (str.length() == 1 || str.charAt(str.length() - 2) != '\\')) {
if (str.charAt(str.length() - 1) == '\\' && (str.length() == 1 || !isEscapedAt(str, str.length() - 1))) {
str += '\\';
}
return brackets != 0
? UNESCAPED.matcher(str).replaceAll("\\\\$0")
? VALUE_ESCAPE.matcher(str).replaceAll("\\\\$0")
: str;
}

public static @NotNull String escape(@NotNull String str) {
if (str.isEmpty()) return str;
return FULL_ESCAPE.matcher(str).replaceAll("\\\\$0");
}

public <R> @NotNull RichOptional<String, R> getOptional(@NotNull String key, @NotNull Function<String, R> converter) {
String value = params.get(key);
return value == null
Expand Down Expand Up @@ -582,22 +594,18 @@ public int hashCode() {
@Override
@Contract("null -> false")
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj instanceof Parameters other) {
if (other.size() != size()) return false;
for (String key : keys()) {
if (!Objects.equals(getString(key), other.getString(key, null))) {
return false;
}
}
return true;
}
return false;
return obj instanceof Parameters otherParams && (otherParams == this || otherParams.origin.equals(origin));
}

@Contract("null -> false")
public boolean equalsFull(@Nullable Parameters params) {
return params != null && (params == this || params.origin.equals(origin));
public boolean isSimilar(@Nullable Parameters other) {
if (other == null || other.size() != size()) return false;
for (String key : keys()) {
if (!Objects.equals(getString(key), other.getString(key, null))) {
return false;
}
}
return true;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
package fun.reactions.placeholders;

import fun.reactions.ReActions;
import fun.reactions.model.environment.Environment;
import fun.reactions.model.environment.Variables;
import fun.reactions.module.basic.placeholders.LocalVarPlaceholder;
import org.mockito.Mockito;
import org.testng.annotations.Test;

import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;

public class ModernPlaceholdersManagerTest {
@Test
public void testParsePlaceholders() {
var platform = Mockito.mock(ReActions.Platform.class);
var mgr = new ModernPlaceholdersManager();
when(platform.getPlaceholders()).thenReturn(mgr);
mgr.registerPlaceholder(new LocalVarPlaceholder());
PlaceholdersManager.setCountLimit(16);
Variables vars = new Variables();
vars.set("test", "y\\ay");
vars.set("another", "%[test]\\,");
assertEquals(
mgr.parse(new Environment(null, "", vars, null, 0), "Foo %[another] bar %[ignored]"),
mgr.parse(new Environment(platform, "", vars, null, 0), "Foo %[another] bar %[ignored]"),
"Foo y\\ay\\, bar %[ignored]"
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ public class NumberUtilsTest {
public static Object[][] parseDoubleData() {
return new Object[][]{
{"3.14", Is.POSITIVE, OptionalDouble.of(3.14)},
{"-5.0", Is.POSITIVE_NATURAL, OptionalDouble.empty()},
{"3.0", Is.NATURAL, OptionalDouble.of(3.0)},
{"7", Is.INTEGER, OptionalDouble.of(7)},
{"3.14", Is.NATURAL, OptionalDouble.empty()},
{"abc", Is.NEGATIVE, OptionalDouble.empty()}
};
}
Expand Down
Loading

0 comments on commit e5d2c26

Please sign in to comment.