From 8c703220b612d99abfaa7397f106be96ff036a9c Mon Sep 17 00:00:00 2001 From: miscoined Date: Mon, 8 Jul 2024 02:39:41 +1000 Subject: [PATCH 01/25] =?UTF-8?q?=F0=9F=90=9B=20Fix=20level=20adjustment?= =?UTF-8?q?=20feat=20text?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Comparison was done with ==, not .equals, so it never triggered. --- .../java/dev/ebullient/convert/tools/pf2e/Json2QuteFeat.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteFeat.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteFeat.java index 6b44546b6..0319aa121 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteFeat.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteFeat.java @@ -2,11 +2,11 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; import com.fasterxml.jackson.databind.JsonNode; -import dev.ebullient.convert.tools.Tags; import dev.ebullient.convert.tools.pf2e.qute.QuteFeat; public class Json2QuteFeat extends Json2QuteBase { @@ -48,7 +48,7 @@ public QuteFeat buildArchetype(String archetypeName, String dedicationLevel) { Tags tags = new Tags(); String note = null; - if (dedicationLevel != featLevel) { + if (!Objects.equals(dedicationLevel, featLevel)) { note = String.format( "> [!pf2-note] This version of %s is intended for use with the %s Archetype. Its level has been changed accordingly.", index.linkify(this.type, String.join("|", List.of(sources.getName(), sources.primarySource()))), From afbf804ff31286b15be80b0b1e7fac855634d743 Mon Sep 17 00:00:00 2001 From: miscoined Date: Tue, 9 Jul 2024 23:23:30 +1000 Subject: [PATCH 02/25] =?UTF-8?q?=F0=9F=90=9B=20Remove=20trailing=20newlin?= =?UTF-8?q?es=20correctly=20from=20ability=20fields?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix an embarrassing regex backreferencing bug where I was accidentally turning all costs into a single 0x01 unicode character - Remove trailing newlines for ability triggers as well --- .../dev/ebullient/convert/tools/pf2e/Json2QuteAbility.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteAbility.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteAbility.java index d31bd8624..941401d47 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteAbility.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteAbility.java @@ -80,8 +80,10 @@ private static QuteAbility createAbility(JsonNode node, JsonSource convert, Pf2e prerequisites.replaceTextFrom(node, convert), cost.replaceTextFrom(node, convert) // remove trailing period - .replaceFirst("^(.*)\\.$", "\1"), - trigger.replaceTextFrom(node, convert), + .replaceFirst("(^[.])\\.$", "$1"), + trigger.replaceTextFrom(node, convert) + // remove trailing period + .replaceFirst("(^[.])\\.$", "$1"), frequency.getFrequencyFrom(node, convert), special.transformTextFrom(node, "\n", convert), note.replaceTextFrom(node, convert), From 94ab73bc5e18e18ee7aec75dfedb42cc75d8fb26 Mon Sep 17 00:00:00 2001 From: miscoined Date: Fri, 19 Jul 2024 03:57:16 +1000 Subject: [PATCH 03/25] =?UTF-8?q?=F0=9F=90=9B=20Fix=20abilities=20getting?= =?UTF-8?q?=20read=20as=20alternate=20stat=20values?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java index a4db54aad..13ca95f25 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java @@ -729,10 +729,11 @@ public static QuteDataNamedBonus getNamedBonus( return new QuteDataNamedBonus( displayName, std.intOrThrow(source), - convert.streamPropsExcluding(source, std, note) + convert.streamPropsExcluding(source, std, note, abilities, notes) .collect(Collectors.toMap(e -> convert.replaceText(e.getKey()), e -> e.getValue().asInt())), - note.getTextFrom(source).map(convert::replaceText).map(List::of) - .orElse((abilities.existsIn(source) ? abilities : notes).replaceTextFromList(source, convert))); + Stream.of(abilities, note, notes) + .flatMap(field -> field.replaceTextFromList(source, convert).stream()) + .toList()); } } From dcb0e7b6fe91ac378d179e332eedeb7491c074de Mon Sep 17 00:00:00 2001 From: miscoined Date: Fri, 5 Jul 2024 23:45:20 +1000 Subject: [PATCH 04/25] =?UTF-8?q?=F0=9F=9A=B8=20Use=20a=20new=20QuteDataRe?= =?UTF-8?q?f=20for=20CreatureSpellReference?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allows template authors to more easily access the components of a note reference rather than just the markdown link text. --- .../convert/tools/pf2e/Json2QuteCreature.java | 4 +- .../convert/tools/pf2e/qute/QuteCreature.java | 19 +++--- .../convert/tools/pf2e/qute/QuteDataRef.java | 68 +++++++++++++++++++ 3 files changed, 80 insertions(+), 11 deletions(-) create mode 100644 src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataRef.java diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteCreature.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteCreature.java index 97f14bcfa..019916f32 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteCreature.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteCreature.java @@ -14,6 +14,7 @@ import dev.ebullient.convert.tools.Tags; import dev.ebullient.convert.tools.pf2e.qute.QuteCreature; +import dev.ebullient.convert.tools.pf2e.qute.QuteDataRef; public class Json2QuteCreature extends Json2QuteBase { @@ -290,7 +291,8 @@ private static QuteCreature.CreatureSpellReference getSpellReference(JsonNode no String spellName = name.getTextOrThrow(node); return new QuteCreature.CreatureSpellReference( spellName, - convert.linkify(Pf2eIndexType.spell, join("|", spellName, source.getTextOrNull(node))), + QuteDataRef.fromMarkdownLink( + convert.linkify(Pf2eIndexType.spell, join("|", spellName, source.getTextOrNull(node)))), amount.getTextFrom(node) .filter(s -> s.equalsIgnoreCase("at will")) .map(unused -> 0) diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteCreature.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteCreature.java index b24c918eb..46d41b6b8 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteCreature.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteCreature.java @@ -11,9 +11,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; -import dev.ebullient.convert.StringUtil; import dev.ebullient.convert.io.JavadocVerbatim; import dev.ebullient.convert.qute.QuteUtil; import dev.ebullient.convert.tools.Tags; @@ -315,7 +313,7 @@ public String toString() { * ``` * * @param name The name of the spell - * @param link A formatted link to the spell's note, or just the spell's name if we couldn't get a link. + * @param spellRef A {@link QuteDataRef} to the spell's note, or null if we couldn't find a note * @param amount The number of casts available for this spell. A value of 0 represents an at will spell. Use * {@link QuteCreature.CreatureSpellReference#formattedAmount()} to get this as a formatted string. * @param notes Any notes associated with this spell, e.g. "at will only" @@ -323,22 +321,23 @@ public String toString() { @TemplateData public record CreatureSpellReference( String name, - String link, + QuteDataRef spellRef, Integer amount, - List notes) { + List notes) implements QuteDataGenericStat { + + @Override + public Integer value() { + return amount; + } /** The number of casts as a formatted string, e.g. "(at will)" or "(×2)". Empty when the amount is 1. */ public String formattedAmount() { return amount == 1 ? "" : parenthesize(amount == 0 ? "at will" : "×" + amount); } - public String formattedNotes() { - return notes.stream().map(StringUtil::parenthesize).collect(Collectors.joining(" ")); - } - @Override public String toString() { - return join(" ", link, formattedAmount(), formattedNotes()); + return join(" ", spellRef == null ? name : spellRef, formattedAmount(), formattedNotes()); } } } diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataRef.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataRef.java new file mode 100644 index 000000000..d7cd43c83 --- /dev/null +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataRef.java @@ -0,0 +1,68 @@ +package dev.ebullient.convert.tools.pf2e.qute; + +import static dev.ebullient.convert.StringUtil.formatIfPresent; +import static dev.ebullient.convert.StringUtil.isPresent; + +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A reference to another note. This will render itself as a formatted link. + * + * @param displayText The display text for the link + * @param notePath The path to the note that this link references. Null if we couldn't find a note to reference. + * @param title The hover title to use for the reference (optional) + */ +public record QuteDataRef(String displayText, String notePath, String title) implements Comparable { + + private static final Pattern MARKDOWN_LINK_PAT = Pattern.compile("^\\[(?[^]]+)]\\((?.*?)(?: \"(?.*)\")?\\)$"); + + public QuteDataRef(String displayText) { + this(displayText, null, null); + } + + public static QuteDataRef fromMarkdownLink(String link) { + if (!isPresent(link)) { + return null; + } + Matcher matcher = MARKDOWN_LINK_PAT.matcher(link); + return matcher.matches() + ? new QuteDataRef(matcher.group("display"), matcher.group("path"), matcher.group("title")) + : new QuteDataRef(link); + } + + /** Return this reference as a Markdown link, without the title attribute. */ + public String withoutTitle() { + return notePath != null ? "[%s](%s)".formatted(displayText, notePath) : displayText; + } + + @Override + public String toString() { + return notePath != null + ? "[%s](%s%s)".formatted(displayText, notePath, formatIfPresent(" \"%s\"", title)) + : displayText; + } + + @Override + public int compareTo(QuteDataRef o) { + if (!displayText.equals(o.displayText)) { + return displayText.compareTo(o.displayText); + } else if (!Objects.equals(notePath, o.notePath)) { + if (notePath == null) { + return -1; + } else if (o.notePath == null) { + return 1; + } + return notePath.compareTo(o.notePath); + } else if (!Objects.equals(title, o.title)) { + if (title == null) { + return -1; + } else if (o.title == null) { + return 1; + } + return title.compareTo(o.title); + } + return 0; + } +} From 844611c618eb0ce9a0ccc88ca444183f1f5d950a Mon Sep 17 00:00:00 2001 From: miscoined <miscoined@gmail.com> Date: Sat, 6 Jul 2024 13:37:04 +1000 Subject: [PATCH 05/25] =?UTF-8?q?=F0=9F=91=94=20Granularize=20AC=20string?= =?UTF-8?q?=20formatting=20and=20remove=20joinWithPrefix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Don't embed the "**AC**" within the AC string - Rename StringUtil.format to formatIfPresent - Remove joinWithPrefix in favour of formatIfPresent - Add some helper template strings for later use in YAML statblocks --- .../dev/ebullient/convert/StringUtil.java | 31 ++----------------- .../convert/tools/pf2e/qute/QuteCreature.java | 10 +++--- .../tools/pf2e/qute/QuteDataArmorClass.java | 7 ++++- .../tools/pf2e/qute/QuteDataDefenses.java | 28 ++++++++++++++--- 4 files changed, 36 insertions(+), 40 deletions(-) diff --git a/src/main/java/dev/ebullient/convert/StringUtil.java b/src/main/java/dev/ebullient/convert/StringUtil.java index 0481bd4df..1f1d380c8 100644 --- a/src/main/java/dev/ebullient/convert/StringUtil.java +++ b/src/main/java/dev/ebullient/convert/StringUtil.java @@ -29,8 +29,8 @@ public class StringUtil { * Return {@code formatString} formatted with {@code o} as the first parameter. * If {@code o} is null, then return an empty string. */ - public static String format(String formatString, Object val) { - return val == null || (val instanceof String && ((String) val).isBlank()) ? "" : formatString.formatted(val); + public static String formatIfPresent(String formatString, Object val) { + return val == null || val.toString().isBlank() ? "" : formatString.formatted(val); } public static String valueOrDefault(String value, String fallback) { @@ -82,33 +82,6 @@ public static String flatJoin(String joiner, Collection<?>... lists) { return join(joiner, Arrays.stream(lists).flatMap(Collection::stream).toList()); } - /** - * Like {@link #joinWithPrefix(String, String, Collection)} but accept vararg inputs. This is mostly to get around - * being unable to pass null values to {@code List.of}. - * - * @see #joinWithPrefix(String, String, Collection) - * @see #join(String, Object, Object...) - */ - public static String joinWithPrefix(String joiner, String prefix, Object o1, Object... rest) { - List<Object> args = new ArrayList<>(); - args.add(o1); - args.addAll(Arrays.asList(rest)); - return joinWithPrefix(joiner, prefix, args); - } - - /** - * Like {@link #join(String, Collection)} but add a prefix to the resulting string if it's non-empty. - * - * @see #join(String, Collection) - */ - public static String joinWithPrefix(String joiner, String prefix, Collection<?> list) { - String s = join(joiner, list); - if (s.isEmpty()) { - return ""; - } - return isPresent(prefix) ? prefix + s : s; - } - /** * {@link #joinConjunct(String, String, List)} with a {@code ", "} joiner. * diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteCreature.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteCreature.java index 46d41b6b8..801c0d464 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteCreature.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteCreature.java @@ -1,7 +1,7 @@ package dev.ebullient.convert.tools.pf2e.qute; import static dev.ebullient.convert.StringUtil.flatJoin; -import static dev.ebullient.convert.StringUtil.format; +import static dev.ebullient.convert.StringUtil.formatIfPresent; import static dev.ebullient.convert.StringUtil.join; import static dev.ebullient.convert.StringUtil.parenthesize; import static dev.ebullient.convert.StringUtil.pluralize; @@ -250,8 +250,8 @@ public String name() { @JavadocVerbatim public String formattedStats() { return join(", ", - format("DC %d", dc), - format("attack %+d", attackBonus), + formatIfPresent("DC %d", dc), + formatIfPresent("attack %+d", attackBonus), focusPoints == null ? "" : focusPoints + " Focus " + pluralize("Point", focusPoints)); } } @@ -299,9 +299,9 @@ public String rank() { @Override public String toString() { return join(" ", - format("**%s**", rank()), + formatIfPresent("**%s**", rank()), join(", ", spells), - format("(%d slots)", slots)); + formatIfPresent("(%d slots)", slots)); } } diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataArmorClass.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataArmorClass.java index 7e72e158d..0511e9b12 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataArmorClass.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataArmorClass.java @@ -47,6 +47,11 @@ private String formattedAlternates(boolean asBonus) { formatMap(alternateValues, (k, v) -> parenthesize(join(" ", valFormat.formatted(v), k)))); } + @Override + public String formattedNotes() { + return flatJoin(", ", List.of(formattedAlternates(false)), notes, abilities); + } + @Override public String bonus() { return join(" ", QuteDataGenericStat.super.bonus(), formattedAlternates(true)); @@ -54,6 +59,6 @@ public String bonus() { @Override public String toString() { - return flatJoin(" ", List.of("**AC**", value, formattedAlternates(false)), notes, abilities); + return join(" ", value, formattedNotes()); } } diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataDefenses.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataDefenses.java index 5fd5abd1d..5080e16ea 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataDefenses.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataDefenses.java @@ -1,13 +1,14 @@ package dev.ebullient.convert.tools.pf2e.qute; +import static dev.ebullient.convert.StringUtil.formatIfPresent; import static dev.ebullient.convert.StringUtil.formatMap; import static dev.ebullient.convert.StringUtil.join; -import static dev.ebullient.convert.StringUtil.joinWithPrefix; import static dev.ebullient.convert.StringUtil.joiningNonEmpty; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.stream.Collectors; import java.util.stream.Stream; import dev.ebullient.convert.qute.QuteUtil; @@ -50,20 +51,37 @@ public record QuteDataDefenses( Map<String, QuteDataGenericStat> resistances, Map<String, QuteDataGenericStat> weaknesses) implements QuteUtil { + @SuppressWarnings("unused") // for template use + public String additionalHp() { + return additionalHpHardnessBt.entrySet().stream() + .filter(e -> e.getValue().hp() != null) + .map(e -> "__%s HP__ %s".formatted(e.getKey(), e.getValue().hp())) + .collect(Collectors.joining("; ")); + } + + @SuppressWarnings("unused") // for template use + public String additionalHardness() { + return additionalHpHardnessBt.entrySet().stream() + .filter(e -> e.getValue().hardness() != null) + .map(e -> "__%s Hardness__ %s".formatted(e.getKey(), e.getValue().hardness())) + .collect(Collectors.joining("; ")); + } + @Override public String toString() { return join("\n", // - **AC** 21; **Fort** +15, **Ref** +12, **Will** +10 - joinWithPrefix("; ", "- ", ac, savingThrows), + formatIfPresent("- %s", + join("; ", formatIfPresent("**AC** %s", ac), savingThrows)), // - **Hardness** 18, **HP (BT)** 10; **Immunities** critical hits; **Resistances** fire 5 - joinWithPrefix("; ", "- ", + formatIfPresent("- %s", join("; ", hpHardnessBt, join("; ", formatMap(additionalHpHardnessBt, (k, v) -> v.toStringWithName(k))), - joinWithPrefix(", ", "**Immunities** ", immunities), + formatIfPresent("**Immunities** %s", join(", ", immunities)), formatMap(resistances, (k, v) -> join(" ", k, v)).stream().sorted() .collect(joiningNonEmpty(", ", "**Resistances** ")), formatMap(weaknesses, (k, v) -> join(" ", k, v)).stream().sorted() - .collect(joiningNonEmpty(", ", "**Weaknesses** ")))); + .collect(joiningNonEmpty(", ", "**Weaknesses** "))))); } /** From a3fa861fc23d11c5fe139ec7cb66d2d0defcb725 Mon Sep 17 00:00:00 2001 From: miscoined <miscoined@gmail.com> Date: Sat, 6 Jul 2024 16:55:44 +1000 Subject: [PATCH 06/25] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Restructure=20QuteDa?= =?UTF-8?q?taActivity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move the enum into QuteDataActivity directly so that we don't have to pass the rule, glyph, and name in every time when it'll be staying the same for a given action. - Make QuteDataActivity store a QuteDataRef to centralize some of the link formatting - Allows template authors to compare the activity itself and theoretically choose what kind of rendering they want --- .../convert/tools/pf2e/Json2QuteDeity.java | 4 +- .../tools/pf2e/JsonTextReplacement.java | 36 ++---- .../convert/tools/pf2e/Pf2eActivity.java | 117 +++++++----------- .../tools/pf2e/Pf2eJsonNodeReader.java | 40 +++--- .../tools/pf2e/qute/QuteDataActivity.java | 41 ++++-- 5 files changed, 103 insertions(+), 135 deletions(-) diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteDeity.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteDeity.java index d63967031..d1ca0ba0a 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteDeity.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteDeity.java @@ -13,7 +13,6 @@ import java.util.TreeMap; import java.util.stream.Collectors; import java.util.stream.Stream; - import com.fasterxml.jackson.databind.JsonNode; import dev.ebullient.convert.StringUtil; @@ -21,6 +20,7 @@ import dev.ebullient.convert.qute.NamedText; import dev.ebullient.convert.tools.Tags; import dev.ebullient.convert.tools.pf2e.Pf2eJsonNodeReader.Pf2eAttack; +import dev.ebullient.convert.tools.pf2e.qute.QuteDataActivity.Activity; import dev.ebullient.convert.tools.pf2e.qute.QuteDeity; import dev.ebullient.convert.tools.pf2e.qute.QuteInlineAttack; import dev.ebullient.convert.tools.pf2e.qute.QuteInlineAttack.AttackRangeType; @@ -176,7 +176,7 @@ private QuteInlineAttack buildAvatarAttack(JsonNode actionNode, Tags tags, Attac return new QuteInlineAttack( Pf2eAttack.name.getTextOrDefault(actionNode, "attack"), - Pf2eActivity.single.toQuteActivity(this, null), + Pf2eActivity.toQuteActivity(this, Activity.single, null), rangeType, Json2QuteItem.Pf2eWeaponData.getDamageString(actionNode, this), Stream.of(Json2QuteItem.Pf2eWeaponData.damageType, Json2QuteItem.Pf2eWeaponData.damageType2) diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/JsonTextReplacement.java b/src/main/java/dev/ebullient/convert/tools/pf2e/JsonTextReplacement.java index 24dc0c4b2..03ff7793a 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/JsonTextReplacement.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/JsonTextReplacement.java @@ -3,6 +3,7 @@ import static dev.ebullient.convert.StringUtil.join; import static dev.ebullient.convert.StringUtil.toAnchorTag; import static dev.ebullient.convert.StringUtil.toTitleCase; +import static dev.ebullient.convert.tools.pf2e.Pf2eActivity.linkifyActivity; import java.util.ArrayList; import java.util.List; @@ -17,6 +18,7 @@ import dev.ebullient.convert.tools.JsonNodeReader; import dev.ebullient.convert.tools.JsonNodeReader.FieldValue; import dev.ebullient.convert.tools.JsonTextConverter; +import dev.ebullient.convert.tools.pf2e.qute.QuteDataActivity.Activity; public interface JsonTextReplacement extends JsonTextConverter<Pf2eIndexType> { @@ -193,31 +195,15 @@ default String replaceFootnoteReference(MatchResult match) { } default String replaceActionAs(MatchResult match) { - final Pf2eActivity type; - switch (match.group(1).toLowerCase()) { - case "1": - case "a": - type = Pf2eActivity.single; - break; - case "2": - case "d": - type = Pf2eActivity.two; - break; - case "3": - case "t": - type = Pf2eActivity.three; - break; - case "f": - type = Pf2eActivity.free; - break; - case "r": - type = Pf2eActivity.reaction; - break; - default: - type = Pf2eActivity.varies; - break; - } - return type.linkify(index().rulesVaultRoot()); + Activity type = switch (match.group(1).toLowerCase()) { + case "1", "a" -> Activity.single; + case "2", "d" -> Activity.two; + case "3", "t" -> Activity.three; + case "f" -> Activity.free; + case "r" -> Activity.reaction; + default -> Activity.varies; + }; + return linkifyActivity(type, index().rulesVaultRoot()); } default String linkifyRuneItem(MatchResult match) { diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eActivity.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eActivity.java index 5b5512920..8f1e68781 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eActivity.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eActivity.java @@ -7,86 +7,55 @@ import dev.ebullient.convert.io.Tui; import dev.ebullient.convert.tools.pf2e.qute.QuteDataActivity; +import dev.ebullient.convert.tools.pf2e.qute.QuteDataActivity.Activity; -public enum Pf2eActivity { - single("Single Action", ">", "single_action.svg"), - two("Two-Action", ">>", "two_actions.svg"), - three("Three-Action", ">>>", "three_actions.svg"), - free("Free Action", "F", "delay.svg"), - reaction("Reaction", "R", "reaction.svg"), - varies("Varies", "V", "load.svg"), - timed("Duration or Frequency", "⏲", "hour-glass.svg"); - +public class Pf2eActivity { final static String DOC_PATH = "core-rulebook/chapter-9-playing-the-game.md#Actions"; - final String longName; - final String markdownName; - final String textGlyph; - final String glyph; - final String targetFileName; - - Pf2eActivity(String longName, String textGlyph, String glyph) { - this.longName = longName; - this.markdownName = longName.replace(" ", "%20"); - this.textGlyph = textGlyph; - this.glyph = glyph; - - int x = glyph.lastIndexOf('.'); - this.targetFileName = Tui.slugify(glyph.substring(0, x)) + glyph.substring(x); - } - - public static Pf2eActivity toActivity(String unit, int number) { - switch (unit) { - case "single": - case "action": - switch (number) { - case 1: - return single; - case 2: - return two; - case 3: - return three; - } - break; - case "free": - return free; - case "reaction": - return reaction; - case "varies": - return varies; - case "timed": - return timed; + public static void addImageRef(Activity activity, JsonSource convert) { + String glyph = switch (activity) { + case single -> "single_action"; + case two -> "two_actions"; + case three -> "three_actions"; + case free -> "delay"; + case reaction -> "reaction"; + case varies -> "load"; + case timed -> "hour-glass"; + }; + String targetFileName = Tui.slugify(glyph) + ".svg"; + Pf2eSources.buildStreamImageRef( + convert.index(), glyph + ".svg", Path.of("img", targetFileName), activity.longName); + } + + public static String linkifyActivity(Activity activity, String rulesRoot) { + return "[%s](%s \"%s\")".formatted(activity.textGlyph, rulesRoot + DOC_PATH, activity.longName); + } + + public static QuteDataActivity toQuteActivity(JsonSource convert, String unit, int number, String text) { + Activity activity = switch (unit) { + case "single", "action" -> switch (number) { + case 1 -> Activity.single; + case 2 -> Activity.two; + case 3 -> Activity.three; + default -> null; + }; + case "free" -> Activity.free; + case "reaction" -> Activity.reaction; + case "varies" -> Activity.varies; + case "timed" -> Activity.timed; + default -> null; + }; + if (activity == null) { + return null; } - return null; - } - - public String getLongName() { - return this.longName; - } - - public String getTextGlyph() { - return this.textGlyph; - } - - public String getGlyph() { - return this.glyph; - } - - public String linkify(String rulesRoot) { - return String.format("[%s](%s \"%s\")", - this.textGlyph, getRulesPath(rulesRoot), longName); - } - - public String getRulesPath(String rulesRoot) { - return String.format("%s%s", rulesRoot, DOC_PATH); + return toQuteActivity(convert, activity, text); } - public QuteDataActivity toQuteActivity(JsonSource convert, String text) { - Path relativeTarget = Path.of("img", targetFileName); + public static QuteDataActivity toQuteActivity(JsonSource convert, Activity activity, String text) { + addImageRef(activity, convert); return new QuteDataActivity( - this != timed && isPresent(text) ? join(" ", getLongName(), text) : text, - Pf2eSources.buildStreamImageRef(convert.index(), glyph, relativeTarget, longName), - textGlyph, - this.getRulesPath(convert.index().rulesVaultRoot())); + activity, + convert.index().rulesVaultRoot() + DOC_PATH, + activity != Activity.timed && isPresent(text) ? join(" ", activity.longName, text) : text); } } diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java index 13ca95f25..045981c3a 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java @@ -17,7 +17,6 @@ import java.util.stream.Collector; import java.util.stream.Collectors; import java.util.stream.Stream; - import com.fasterxml.jackson.databind.JsonNode; import dev.ebullient.convert.StringUtil; @@ -27,6 +26,7 @@ import dev.ebullient.convert.tools.pf2e.JsonSource.AppendTypeValue; import dev.ebullient.convert.tools.pf2e.qute.QuteAbilityOrAffliction; import dev.ebullient.convert.tools.pf2e.qute.QuteDataActivity; +import dev.ebullient.convert.tools.pf2e.qute.QuteDataActivity.Activity; import dev.ebullient.convert.tools.pf2e.qute.QuteDataArmorClass; import dev.ebullient.convert.tools.pf2e.qute.QuteDataDefenses; import dev.ebullient.convert.tools.pf2e.qute.QuteDataDuration; @@ -518,26 +518,21 @@ enum Pf2eNumberUnitEntry implements Pf2eJsonNodeReader { */ private static QuteDataActivity getActivity(JsonNode node, JsonSource convert) { String actionType = unit.getTextOrNull(node); - Pf2eActivity activity = switch (actionType) { - case "single", "action", "free", "reaction" -> - Pf2eActivity.toActivity(actionType, number.intOrThrow(node)); - case "varies" -> Pf2eActivity.varies; - case "day", "minute", "hour", "round" -> Pf2eActivity.timed; - default -> null; - }; - - if (activity == null) { - throw new IllegalArgumentException("Can't parse activity from: %s".formatted(node)); - } String extra = entry.getTextFrom(node) - .filter(s -> !s.toLowerCase().contains("varies")) - .filter(Predicate.not(String::isBlank)) - .map(convert::replaceText).map(StringUtil::parenthesize) - .orElse(""); - - return activity.toQuteActivity( - convert, activity == Pf2eActivity.timed ? join(" ", number.intOrThrow(node), actionType, extra) : extra); + .filter(s -> !s.toLowerCase().contains("varies")) + .filter(Predicate.not(String::isBlank)) + .map(convert::replaceText).map(StringUtil::parenthesize) + .orElse(""); + + return switch (actionType) { + case "single", "action", "free", "reaction", "varies" -> + Pf2eActivity.toQuteActivity(convert, actionType, number.intOrDefault(node, 0), extra); + case "day", "minute", "hour", "round" -> + Pf2eActivity.toQuteActivity( + convert, Activity.timed, join(" ", number.intOrThrow(node), actionType, extra)); + default -> throw new IllegalArgumentException("Can't parse activity from: %s".formatted(node)); + }; } /** @@ -565,9 +560,8 @@ private static QuteDataDuration getDuration(JsonNode node, JsonSource convert) { return null; } // The activity is more specific unless we have a custom display. Otherwise, fall back to the timed duration - return Optional.ofNullable(Pf2eActivity.toActivity(unitText, timedDuration.value())) - .map(a -> (QuteDataDuration) a.toQuteActivity(convert, null)) - .orElse(timedDuration); + return requireNonNullElse( + Pf2eActivity.toQuteActivity(convert, unitText, timedDuration.value(), null), timedDuration); } /** @@ -677,7 +671,7 @@ public static QuteInlineAttack getAttack(JsonNode node, JsonSource convert) { return new QuteInlineAttack( name.replaceTextFrom(node, convert), Optional.ofNullable(activity.getActivityFrom(node, convert)) - .orElse(Pf2eActivity.single.toQuteActivity(convert, "")), + .orElse(Pf2eActivity.toQuteActivity(convert, Activity.single, "")), QuteInlineAttack.AttackRangeType.valueOf(range.getTextOrDefault(node, "Melee").toUpperCase()), attack.intOrNull(node), formattedDamage, diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataActivity.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataActivity.java index f89ad9a53..94fa2d200 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataActivity.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataActivity.java @@ -2,7 +2,6 @@ import static dev.ebullient.convert.StringUtil.join; -import dev.ebullient.convert.qute.ImageRef; import dev.ebullient.convert.qute.QuteUtil; import io.quarkus.qute.TemplateData; @@ -10,25 +9,45 @@ * Pf2eTools activity attributes. This attribute will render itself as a formatted link: * * <pre> - * [textGlyph](rulesPath "glyph.title")<optional text> + * [textGlyph](rulesPath "action name")<optional text> * </pre> * - * @param text The text associated with the action - may be null. - * @param glyph icon/image representing this activity as a {@link dev.ebullient.convert.qute.ImageRef ImageRef} - * @param textGlyph A textual representation of the glyph, used as the link text - * @param rulesPath The path which leads to an explanation of this particular activity + * @param activity The type of activity, as a {@link QuteDataActivity.Activity} + * @param actionRef A {@link QuteDataRef} to the rules for this particular action type + * @param note Text associated with this activity */ @TemplateData -public record QuteDataActivity(String text, ImageRef glyph, String textGlyph, - String rulesPath) implements QuteUtil, QuteDataDuration { +public record QuteDataActivity(Activity activity, QuteDataRef actionRef, String note) implements QuteUtil, QuteDataDuration { + + public QuteDataActivity(Activity activity, String rulesPath, String note) { + this(activity, new QuteDataRef(activity.textGlyph, rulesPath, activity.longName), note); + } /** Return the text associated with the action. */ - @Override public String text() { - return isPresent(text) ? text : glyph.title; + return isPresent(note) ? note : activity.longName; } + @Override public String toString() { - return join(" ", "[%s](%s \"%s\")".formatted(textGlyph, rulesPath, glyph.title), text); + return join(" ", actionRef.toString(), note); + } + + public enum Activity { + single("Single Action", ">"), + two("Two-Action", ">>"), + three("Three-Action", ">>>"), + free("Free Action", "F"), + reaction("Reaction", "R"), + varies("Varies", "V"), + timed("Duration or Frequency", "⏲"); + + public final String longName; + public final String textGlyph; + + Activity(String longName, String textGlyph) { + this.longName = longName; + this.textGlyph = textGlyph; + } } } From 658ccb74d29264b6a1fc455f682d0cb54e4e2402 Mon Sep 17 00:00:00 2001 From: miscoined <miscoined@gmail.com> Date: Sun, 7 Jul 2024 20:31:07 +1000 Subject: [PATCH 07/25] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Remove=20renderInlin?= =?UTF-8?q?eTemplate=20and=20friends?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace with renderEmbeddedTemplate. This will make the next changes easier. --- .../convert/tools/JsonTextConverter.java | 47 ++++--------------- .../convert/tools/dnd5e/JsonSource.java | 9 ++-- .../tools/pf2e/Json2QuteArchetype.java | 9 ++-- .../convert/tools/pf2e/JsonSource.java | 4 +- .../tools/pf2e/qute/QuteAffliction.java | 2 +- .../tools/pf2e/qute/QuteInlineAttack.java | 2 +- 6 files changed, 19 insertions(+), 54 deletions(-) diff --git a/src/main/java/dev/ebullient/convert/tools/JsonTextConverter.java b/src/main/java/dev/ebullient/convert/tools/JsonTextConverter.java index f06d226a9..0978344e4 100644 --- a/src/main/java/dev/ebullient/convert/tools/JsonTextConverter.java +++ b/src/main/java/dev/ebullient/convert/tools/JsonTextConverter.java @@ -495,9 +495,9 @@ default List<String> removePreamble(List<String> content) { * @param resource QuteBase containing required template resource data * @param admonition Type of embedded/encapsulating admonition */ - default String renderEmbeddedTemplate(QuteBase resource, String admonition) { + default String renderEmbeddedTemplate(QuteUtil resource, String admonition, String... prepend) { List<String> inner = new ArrayList<>(); - renderEmbeddedTemplate(inner, resource, admonition, List.of()); + renderEmbeddedTemplate(inner, resource, admonition, prepend); return String.join("\n", inner); } @@ -509,11 +509,11 @@ default String renderEmbeddedTemplate(QuteBase resource, String admonition) { * @param admonition Type of embedded/encapsulating admonition * @param prepend Text to prepend at beginning of admonition (e.g. title) */ - default void renderEmbeddedTemplate(List<String> text, QuteBase resource, String admonition, List<String> prepend) { - boolean pushed = parseState().push(resource.sources()); + default void renderEmbeddedTemplate(List<String> text, QuteUtil resource, String admonition, String... prepend) { + Boolean pushed = (resource instanceof QuteBase) ? parseState().push(((QuteBase)resource).sources()) : null; try { String rendered = tui().renderEmbedded(resource); - List<String> inner = new ArrayList<>(prepend); + List<String> inner = new ArrayList<>(Arrays.asList(prepend)); inner.addAll(removePreamble(new ArrayList<>(List.of(rendered.split("\n"))))); maybeAddBlankLine(text); @@ -524,41 +524,10 @@ default void renderEmbeddedTemplate(List<String> text, QuteBase resource, String } text.addAll(inner); } finally { - parseState().pop(pushed); - } - } - - /** - * Return the rendered contents of an (always) inline template. - * - * @param resource QuteUtil containing required template resource data - * @param admonition Type of inline admonition - */ - default String renderInlineTemplate(QuteUtil resource, String admonition) { - List<String> inner = new ArrayList<>(); - renderInlineTemplate(inner, resource, admonition); - return String.join("\n", inner); - } - - /** - * Add rendered contents of an (always) inline template - * to collected text - * - * @param text List of text content should be added to - * @param resource QuteUtil containing required template resource data - * @param admonition Type of inline admonition - */ - default void renderInlineTemplate(List<String> text, QuteUtil resource, String admonition) { - String rendered = tui().renderEmbedded(resource); - List<String> inner = removePreamble(new ArrayList<>(List.of(rendered.split("\n")))); - - maybeAddBlankLine(text); - if (admonition != null) { - wrapAdmonition(inner, "inline-" + admonition); - } else { - balanceBackticks(inner); + if (pushed != null) { + parseState().pop(pushed); + } } - text.addAll(inner); } /** Wrap {@code inner} in an admonition with the name {@code admonition}. */ diff --git a/src/main/java/dev/ebullient/convert/tools/dnd5e/JsonSource.java b/src/main/java/dev/ebullient/convert/tools/dnd5e/JsonSource.java index b03115721..7d638202a 100644 --- a/src/main/java/dev/ebullient/convert/tools/dnd5e/JsonSource.java +++ b/src/main/java/dev/ebullient/convert/tools/dnd5e/JsonSource.java @@ -605,11 +605,10 @@ default void appendStatblockInline(List<String> text, JsonNode entry, String hea .withTargetFile(embedFileName) .withTargetPath(relativePath)); } else { - List<String> prepend = new ArrayList<>(List.of( - "title: " + name, - "collapse: closed", - existingNode == null ? "" : "%% See " + type.linkify(this, data) + " %%")); - renderEmbeddedTemplate(text, qs, type.name(), prepend); + renderEmbeddedTemplate(text, qs, type.name(), + "title: " + name, + "collapse: closed", + existingNode == null ? "" : "%% See " + type.linkify(this, data) + " %%"); } } } diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteArchetype.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteArchetype.java index 4590a25fb..700957e43 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteArchetype.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteArchetype.java @@ -120,12 +120,9 @@ QuteFeat findFeat(String levelKey) { } String render(QuteFeat quteFeat, boolean archetypeFeat) { - List<String> inner = new ArrayList<>(); - renderEmbeddedTemplate(inner, quteFeat, "feat", List.of( - String.format("title: %s, Feat %s", quteFeat.getName(), quteFeat.level + (archetypeFeat ? "*" : "")), - "collapse: closed")); - - return String.join("\n", inner); + return renderEmbeddedTemplate(quteFeat, "feat", + "title: %s, Feat %s".formatted(quteFeat.getName(), quteFeat.level + (archetypeFeat ? "*" : "")), + "collapse: closed"); } enum ArchetypeField implements Pf2eJsonNodeReader { diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java b/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java index 79ac45ff8..773dec489 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java @@ -578,8 +578,8 @@ default void embedData(List<String> text, JsonNode dataNode) { Pf2eQuteBase converted = dataType.convertJson2QuteBase(index(), data); if (converted != null) { renderEmbeddedTemplate(text, converted, tag, - List.of(String.format("title: %s", converted.title()), - "collapse: closed")); + "title: %s".formatted(converted.title()), + "collapse: closed"); } else { tui().errorf("Unable to process data for %s: %s", tag, dataNode.toString()); } diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAffliction.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAffliction.java index 25068da6e..aa3b2660c 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAffliction.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAffliction.java @@ -96,7 +96,7 @@ public String template() { @Override public String render() { - return _converter.renderInlineTemplate(this, null); + return _converter.renderEmbeddedTemplate(this, null); } @Override diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteInlineAttack.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteInlineAttack.java index 071c97558..1078a0e24 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteInlineAttack.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteInlineAttack.java @@ -108,7 +108,7 @@ public String template() { @Override public String render() { - return _converter.renderInlineTemplate(this, null); + return _converter.renderEmbeddedTemplate(this, null); } @Override From 395971ea254a1b18059b68a95c252bdd3dbf3428 Mon Sep 17 00:00:00 2001 From: miscoined <miscoined@gmail.com> Date: Sun, 7 Jul 2024 23:36:59 +1000 Subject: [PATCH 08/25] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Pull=20embedded=20ab?= =?UTF-8?q?ility=20construction=20into=20Json2QuteAbility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Generally pull things up into the main class rather than methods of the JsonNodeReader. --- .../convert/tools/pf2e/Json2QuteAbility.java | 21 ++++++++++--------- .../convert/tools/pf2e/Json2QuteHazard.java | 4 +--- .../convert/tools/pf2e/JsonSource.java | 7 +++---- .../tools/pf2e/Pf2eJsonNodeReader.java | 3 +-- .../convert/tools/pf2e/Pf2eMarkdown.java | 2 +- 5 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteAbility.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteAbility.java index 941401d47..ef0f35b04 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteAbility.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteAbility.java @@ -12,13 +12,17 @@ public class Json2QuteAbility extends Json2QuteBase { - public Json2QuteAbility(Pf2eIndex index, Pf2eIndexType type, JsonNode rootNode) { - super(index, type, rootNode); + private final boolean isEmbedded; + + public Json2QuteAbility(Pf2eIndex index, JsonNode rootNode, boolean isEmbedded) { + super(index, Pf2eIndexType.ability, rootNode, + isEmbedded ? null : Pf2eSources.findOrTemporary(Pf2eIndexType.ability, rootNode)); + this.isEmbedded = isEmbedded; } @Override protected QuteAbility buildQuteNote() { - return Pf2eAbility.createAbility(rootNode, this, sources); + return Pf2eAbility.createAbility(this); } public enum Pf2eAbility implements Pf2eJsonNodeReader { @@ -63,11 +67,12 @@ public enum Pf2eAbility implements Pf2eJsonNodeReader { /** Nestable entries for the ability effect. */ entries; - private static QuteAbility createAbility(JsonNode node, JsonSource convert, Pf2eSources sources) { + private static QuteAbility createAbility(Json2QuteAbility convert) { + JsonNode node = convert.rootNode; Tags tags = new Tags(); Set<String> traits = convert.collectTraitsFrom(node, tags); - return new QuteAbility(sources, + return new QuteAbility(convert.sources, name.getTextFrom(node).map(convert::replaceText).orElse("Activate"), generic.getLinkFrom(node, convert), entries.transformTextFrom(node, "\n", convert), @@ -87,11 +92,7 @@ private static QuteAbility createAbility(JsonNode node, JsonSource convert, Pf2e frequency.getFrequencyFrom(node, convert), special.transformTextFrom(node, "\n", convert), note.replaceTextFrom(node, convert), - sources == null, convert); - } - - public static QuteAbility createEmbeddedAbility(JsonNode node, JsonSource convert) { - return createAbility(node, convert, null); + convert.isEmbedded, convert); } public String getLinkFrom(JsonNode node, JsonSource convert) { diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteHazard.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteHazard.java index 07fa0e798..6488320e8 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteHazard.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteHazard.java @@ -2,12 +2,10 @@ import java.util.ArrayList; import java.util.List; - import com.fasterxml.jackson.databind.JsonNode; import dev.ebullient.convert.tools.JsonTextConverter; import dev.ebullient.convert.tools.Tags; -import dev.ebullient.convert.tools.pf2e.Json2QuteAbility.Pf2eAbility; import dev.ebullient.convert.tools.pf2e.qute.QuteDataGenericStat; import dev.ebullient.convert.tools.pf2e.qute.QuteHazard; @@ -33,7 +31,7 @@ protected QuteHazard buildQuteResource() { Pf2eHazard.defenses.getDefensesFrom(rootNode, this), Pf2eHazard.attacks.getAttacksFrom(rootNode, this), Pf2eHazard.abilities.streamFrom(rootNode) - .map(n -> Pf2eAbility.createEmbeddedAbility(n, this)) + .map(n -> new Json2QuteAbility(index, n, true).buildQuteNote()) .toList(), Pf2eHazard.actions.getAbilityOrAfflictionsFrom(rootNode, this), Pf2eHazard.stealth.getObjectFrom(rootNode) diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java b/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java index 773dec489..0e37f7a48 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java @@ -8,7 +8,6 @@ import java.util.Set; import java.util.TreeSet; import java.util.stream.Collectors; - import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; @@ -18,7 +17,6 @@ import dev.ebullient.convert.qute.QuteUtil; import dev.ebullient.convert.tools.JsonNodeReader.FieldValue; import dev.ebullient.convert.tools.Tags; -import dev.ebullient.convert.tools.pf2e.Json2QuteAbility.Pf2eAbility; import dev.ebullient.convert.tools.pf2e.Json2QuteAffliction.Pf2eAffliction; import dev.ebullient.convert.tools.pf2e.Json2QuteItem.Pf2eItem; import dev.ebullient.convert.tools.pf2e.qute.Pf2eQuteBase; @@ -115,7 +113,8 @@ default void appendObjectToText(List<String> text, JsonNode node, String heading case quote -> appendQuote(text, node); // special inline types - case ability -> appendRenderable(text, Pf2eAbility.createEmbeddedAbility(node, this)); + case ability -> appendRenderable(text, + new Json2QuteAbility(index(), node, true).buildQuteNote()); case affliction -> appendAffliction(text, node); case attack -> appendRenderable(text, Pf2eJsonNodeReader.Pf2eAttack.getAttack(node, this)); case data -> embedData(text, node); @@ -556,7 +555,7 @@ default void embedData(List<String> text, JsonNode dataNode) { // So try to get the renderable embedded object first, and then add the collapsed // tag to the outermost admonition. QuteUtil.Renderable renderable = switch (dataType) { - case ability -> Pf2eAbility.createEmbeddedAbility(data, this); + case ability -> new Json2QuteAbility(index(), data, true).buildQuteNote(); case affliction, curse, disease -> Pf2eAffliction.createInlineAffliction(data, this); default -> null; }; diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java index 045981c3a..b136d1273 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java @@ -21,7 +21,6 @@ import dev.ebullient.convert.StringUtil; import dev.ebullient.convert.tools.JsonNodeReader; -import dev.ebullient.convert.tools.pf2e.Json2QuteAbility.Pf2eAbility; import dev.ebullient.convert.tools.pf2e.Json2QuteAffliction.Pf2eAffliction; import dev.ebullient.convert.tools.pf2e.JsonSource.AppendTypeValue; import dev.ebullient.convert.tools.pf2e.qute.QuteAbilityOrAffliction; @@ -134,7 +133,7 @@ default List<QuteAbilityOrAffliction> getAbilityOrAfflictionsFrom(JsonNode sourc return streamFrom(source) .map(n -> switch (requireNonNullElse(AppendTypeValue.getBlockType(n), AppendTypeValue.ability)) { case affliction -> (QuteAbilityOrAffliction) Pf2eAffliction.createInlineAffliction(n, convert); - case ability -> Pf2eAbility.createEmbeddedAbility(n, convert); + case ability -> (QuteAbilityOrAffliction) new Json2QuteAbility(convert.index(), n, true).buildQuteNote(); default -> { convert.tui().debugf("Unexpected block type in %s", source.toPrettyString()); yield null; diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eMarkdown.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eMarkdown.java index 569eda6b9..44a2b80c2 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eMarkdown.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eMarkdown.java @@ -107,7 +107,7 @@ private Pf2eMarkdown writeNotesAndTables(List<? extends IndexType> types) { } switch (type) { - case ability -> rules.add(new Json2QuteAbility(index, type, node).buildNote()); + case ability -> rules.add(new Json2QuteAbility(index, node, false).buildNote()); case affliction, curse, disease -> compendium.add(new Json2QuteAffliction(index, type, node).buildNote()); case book -> { From 5d15e0cc665c885ed9e7f95dfd46fe1246c91c8a Mon Sep 17 00:00:00 2001 From: miscoined <miscoined@gmail.com> Date: Mon, 8 Jul 2024 00:03:55 +1000 Subject: [PATCH 09/25] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Pull=20embedded=20Qu?= =?UTF-8?q?teAffliction=20creation=20into=20Json2QuteAffliction?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tools/pf2e/Json2QuteAffliction.java | 28 +++++++++---------- .../convert/tools/pf2e/JsonSource.java | 19 +++++-------- .../tools/pf2e/Pf2eJsonNodeReader.java | 6 ++-- .../convert/tools/pf2e/Pf2eMarkdown.java | 2 +- 4 files changed, 24 insertions(+), 31 deletions(-) diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteAffliction.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteAffliction.java index 3d2b73765..86ceeb892 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteAffliction.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteAffliction.java @@ -21,13 +21,16 @@ public class Json2QuteAffliction extends Json2QuteBase { - public Json2QuteAffliction(Pf2eIndex index, Pf2eIndexType type, JsonNode rootNode) { - super(index, type, rootNode); + private final boolean isEmbedded; + + public Json2QuteAffliction(Pf2eIndex index, Pf2eIndexType type, JsonNode rootNode, boolean isEmbedded) { + super(index, type, rootNode, isEmbedded ? null : Pf2eSources.findOrTemporary(type, rootNode)); + this.isEmbedded = isEmbedded; } @Override protected QuteAffliction buildQuteNote() { - return Pf2eAffliction.createAffliction(rootNode, this, getSources()); + return Pf2eAffliction.createAffliction(this); } public enum Pf2eAffliction implements Pf2eJsonNodeReader { @@ -96,20 +99,19 @@ public enum Pf2eAffliction implements Pf2eJsonNodeReader { * ], * </pre> */ - private static QuteAffliction createAffliction( - JsonNode node, JsonSource convert, Pf2eSources sources) { - boolean isEmbedded = sources == null; + private static QuteAffliction createAffliction(Json2QuteAffliction convert) { + JsonNode node = convert.rootNode; // Sometimes the affliction data is nested as an entry within the parent node. Optional<JsonNode> nestedAfflictionNode = Optional.ofNullable(getNestedAffliction(node)); - if (!isEmbedded && nestedAfflictionNode.isEmpty()) { + if (!convert.isEmbedded && nestedAfflictionNode.isEmpty()) { // For standalone notes, we should always have a nested affliction node. convert.tui().errorf("Unable to extract affliction entry from %s", node.toPrettyString()); return null; } JsonNode dataNode = nestedAfflictionNode.orElse(node); - Tags tags = new Tags(sources); + Tags tags = new Tags(convert.sources); Collection<String> traits = convert.collectTraitsFrom(node, tags); Optional<String> afflictionLevel = level.intFrom(node).map(Objects::toString); @@ -130,9 +132,9 @@ private static QuteAffliction createAffliction( Optional<String> afflictionName = name.getTextFrom(node); return new QuteAffliction( - sources, + convert.sources, // Standalone notes must have a valid affliction name so that we can name the file - isEmbedded ? afflictionName.orElse("") : afflictionName.orElseThrow(), + convert.isEmbedded ? afflictionName.orElse("") : afflictionName.orElseThrow(), // Any entries which were alongside the nested affliction block nestedAfflictionNode.isEmpty() ? List.of() @@ -177,14 +179,10 @@ private static QuteAffliction createAffliction( entry.transformTextFrom(e.getValue(), "\n", convert, e.getKey())), (x, y) -> y, LinkedHashMap::new)), - isEmbedded, + convert.isEmbedded, convert); } - static QuteAffliction createInlineAffliction(JsonNode node, JsonSource convert) { - return createAffliction(node, convert, null); - } - /** Try to extract the affliction node from the entries. Returns null if we couldn't extract one. */ private static JsonNode getNestedAffliction(JsonNode node) { if (!entries.isArrayIn(node)) { diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java b/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java index 0e37f7a48..d4a9e1353 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java @@ -17,7 +17,6 @@ import dev.ebullient.convert.qute.QuteUtil; import dev.ebullient.convert.tools.JsonNodeReader.FieldValue; import dev.ebullient.convert.tools.Tags; -import dev.ebullient.convert.tools.pf2e.Json2QuteAffliction.Pf2eAffliction; import dev.ebullient.convert.tools.pf2e.Json2QuteItem.Pf2eItem; import dev.ebullient.convert.tools.pf2e.qute.Pf2eQuteBase; import dev.ebullient.convert.tools.pf2e.qute.QuteDataActivity; @@ -115,7 +114,8 @@ default void appendObjectToText(List<String> text, JsonNode node, String heading // special inline types case ability -> appendRenderable(text, new Json2QuteAbility(index(), node, true).buildQuteNote()); - case affliction -> appendAffliction(text, node); + case affliction -> appendRenderable(text, + new Json2QuteAffliction(index(), Pf2eIndexType.affliction, node, true).buildQuteNote()); case attack -> appendRenderable(text, Pf2eJsonNodeReader.Pf2eAttack.getAttack(node, this)); case data -> embedData(text, node); case lvlEffect -> appendLevelEffect(text, node); @@ -298,11 +298,6 @@ default void appendSuccessDegree(List<String> text, JsonNode node) { + x)); } - /** Internal */ - default void appendAffliction(List<String> text, JsonNode node) { - appendRenderable(text, Pf2eAffliction.createInlineAffliction(node, this)); - } - /** Internal */ private void appendRenderable(List<String> text, QuteUtil.Renderable renderable) { text.addAll(List.of(renderable.render().split("\n"))); @@ -554,14 +549,14 @@ default void embedData(List<String> text, JsonNode dataNode) { // (This might be the case anyway, but we know it probably is the case with these). // So try to get the renderable embedded object first, and then add the collapsed // tag to the outermost admonition. - QuteUtil.Renderable renderable = switch (dataType) { - case ability -> new Json2QuteAbility(index(), data, true).buildQuteNote(); - case affliction, curse, disease -> Pf2eAffliction.createInlineAffliction(data, this); + Json2QuteBase json2Renderable = switch (dataType) { + case ability -> new Json2QuteAbility(index(), data, true); + case affliction, curse, disease -> new Json2QuteAffliction(index(), dataType, data, true); default -> null; }; - if (renderable != null) { + if (json2Renderable != null) { List<String> renderedData = new ArrayList<>(); - appendRenderable(renderedData, renderable); + appendRenderable(renderedData, (QuteUtil.Renderable) json2Renderable.buildQuteNote()); // Make the outermost admonition collapsed, if there is one int[] adIndices = outerAdmonitionIndices(renderedData); if (adIndices != null) { diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java index b136d1273..c27140433 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java @@ -21,7 +21,6 @@ import dev.ebullient.convert.StringUtil; import dev.ebullient.convert.tools.JsonNodeReader; -import dev.ebullient.convert.tools.pf2e.Json2QuteAffliction.Pf2eAffliction; import dev.ebullient.convert.tools.pf2e.JsonSource.AppendTypeValue; import dev.ebullient.convert.tools.pf2e.qute.QuteAbilityOrAffliction; import dev.ebullient.convert.tools.pf2e.qute.QuteDataActivity; @@ -132,14 +131,15 @@ default List<String> getActivationComponentsFrom(JsonNode source, Set<String> tr default List<QuteAbilityOrAffliction> getAbilityOrAfflictionsFrom(JsonNode source, JsonSource convert) { return streamFrom(source) .map(n -> switch (requireNonNullElse(AppendTypeValue.getBlockType(n), AppendTypeValue.ability)) { - case affliction -> (QuteAbilityOrAffliction) Pf2eAffliction.createInlineAffliction(n, convert); - case ability -> (QuteAbilityOrAffliction) new Json2QuteAbility(convert.index(), n, true).buildQuteNote(); + case affliction -> new Json2QuteAffliction(convert.index(), Pf2eIndexType.affliction, n, true); + case ability -> new Json2QuteAbility(convert.index(), n, true); default -> { convert.tui().debugf("Unexpected block type in %s", source.toPrettyString()); yield null; } }) .filter(Objects::nonNull) + .map(json2Qute -> (QuteAbilityOrAffliction) json2Qute.buildNote()) .toList(); } diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eMarkdown.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eMarkdown.java index 44a2b80c2..613ef1f3f 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eMarkdown.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eMarkdown.java @@ -109,7 +109,7 @@ private Pf2eMarkdown writeNotesAndTables(List<? extends IndexType> types) { switch (type) { case ability -> rules.add(new Json2QuteAbility(index, node, false).buildNote()); case affliction, curse, disease -> - compendium.add(new Json2QuteAffliction(index, type, node).buildNote()); + compendium.add(new Json2QuteAffliction(index, type, node, false).buildNote()); case book -> { index.tui().progressf("book %s", e.getKey()); JsonNode data = index.getIncludedNode(key.replace("book|", "data|")); From dfbdc231201e3213a3e552568fabdf4e71da876f Mon Sep 17 00:00:00 2001 From: miscoined <miscoined@gmail.com> Date: Mon, 8 Jul 2024 01:18:01 +1000 Subject: [PATCH 10/25] =?UTF-8?q?=E2=99=BB=EF=B8=8F=F0=9F=90=9B=20Centrali?= =?UTF-8?q?ze=20some=20common=20note=20code,=20fixing=20some=20tagging=20b?= =?UTF-8?q?ugs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move entries, traits, and tags into Json2QuteBase - Incidentally fix a few cases where tags aren't populated correctly --- .../convert/tools/JsonNodeReader.java | 9 ++++-- .../convert/tools/pf2e/Json2QuteAbility.java | 14 +++------- .../convert/tools/pf2e/Json2QuteAction.java | 11 ++------ .../tools/pf2e/Json2QuteAffliction.java | 16 ++++------- .../tools/pf2e/Json2QuteArchetype.java | 10 +------ .../tools/pf2e/Json2QuteBackground.java | 11 +------- .../convert/tools/pf2e/Json2QuteBase.java | 10 +++++++ .../convert/tools/pf2e/Json2QuteCreature.java | 17 ++++------- .../convert/tools/pf2e/Json2QuteDeity.java | 17 ++++------- .../convert/tools/pf2e/Json2QuteFeat.java | 17 ++--------- .../convert/tools/pf2e/Json2QuteHazard.java | 11 ++------ .../convert/tools/pf2e/Json2QuteItem.java | 28 +++++++------------ .../convert/tools/pf2e/Json2QuteRitual.java | 16 +++-------- .../convert/tools/pf2e/Json2QuteSpell.java | 15 ++-------- .../convert/tools/pf2e/Json2QuteTable.java | 4 --- .../convert/tools/pf2e/Json2QuteTrait.java | 10 ++----- .../convert/tools/pf2e/qute/QuteAbility.java | 2 +- .../convert/tools/pf2e/qute/QuteCreature.java | 2 +- 18 files changed, 66 insertions(+), 154 deletions(-) diff --git a/src/main/java/dev/ebullient/convert/tools/JsonNodeReader.java b/src/main/java/dev/ebullient/convert/tools/JsonNodeReader.java index 9877497e6..79a298a73 100644 --- a/src/main/java/dev/ebullient/convert/tools/JsonNodeReader.java +++ b/src/main/java/dev/ebullient/convert/tools/JsonNodeReader.java @@ -364,15 +364,20 @@ default String transformTextFrom(JsonNode source, String delimiter, JsonTextConv * Parse this field from {@code source} as potentially-nested array of entries, and return a list of strings. This * calls {@link JsonTextConverter#appendToText(List, JsonNode, String)} to recursively parse the input. */ - default List<String> transformListFrom(JsonNode source, JsonTextConverter<?> convert) { + default List<String> transformListFrom(JsonNode source, JsonTextConverter<?> convert, String heading) { if (!isArrayIn(source)) { return List.of(); } List<String> inner = new ArrayList<>(); - convert.appendToText(inner, getFrom(source), null); + convert.appendToText(inner, getFrom(source), heading); return inner; } + /** @see #transformListFrom(JsonNode, JsonTextConverter, String) */ + default List<String> transformListFrom(JsonNode source, JsonTextConverter<?> convert) { + return transformListFrom(source, convert, null); + } + /** Returns the enum value of {@code enumClass} that this field in {@code source} contains, or null. */ default <E extends Enum<E>> E getEnumValueFrom(JsonNode source, Class<E> enumClass) { String value = getTextOrNull(source); diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteAbility.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteAbility.java index ef0f35b04..3727f366e 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteAbility.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteAbility.java @@ -3,11 +3,8 @@ import static dev.ebullient.convert.StringUtil.join; import static dev.ebullient.convert.StringUtil.parenthesize; -import java.util.Set; - import com.fasterxml.jackson.databind.JsonNode; -import dev.ebullient.convert.tools.Tags; import dev.ebullient.convert.tools.pf2e.qute.QuteAbility; public class Json2QuteAbility extends Json2QuteBase { @@ -69,18 +66,15 @@ public enum Pf2eAbility implements Pf2eJsonNodeReader { private static QuteAbility createAbility(Json2QuteAbility convert) { JsonNode node = convert.rootNode; - Tags tags = new Tags(); - Set<String> traits = convert.collectTraitsFrom(node, tags); - return new QuteAbility(convert.sources, name.getTextFrom(node).map(convert::replaceText).orElse("Activate"), generic.getLinkFrom(node, convert), - entries.transformTextFrom(node, "\n", convert), - tags, - traits, + convert.entries, + convert.tags, + convert.traits, activity.getActivityFrom(node, convert), range.getRangeFrom(node, convert), - components.getActivationComponentsFrom(node, traits, convert), + components.getActivationComponentsFrom(node, convert.traits, convert), requirements.replaceTextFrom(node, convert), prerequisites.replaceTextFrom(node, convert), cost.replaceTextFrom(node, convert) diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteAction.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteAction.java index 3ad2b2f4f..4ad8944b2 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteAction.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteAction.java @@ -19,11 +19,7 @@ public Json2QuteAction(Pf2eIndex index, JsonNode node) { @Override protected QuteAction buildQuteResource() { - Tags tags = new Tags(sources); - List<String> text = new ArrayList<>(); - - appendToText(text, SourceField.entries.getFrom(rootNode), "##"); - appendToText(text, Pf2eAction.info.getFrom(rootNode), null); + entries.addAll(Pf2eAction.info.transformListFrom(rootNode, this)); ActionType actionType = Pf2eAction.actionType.fieldFromTo(rootNode, ActionType.class, tui()); @@ -33,12 +29,11 @@ protected QuteAction buildQuteResource() { actionType.addTags(this, tags); } - return new QuteAction( - getSources(), text, tags, + return new QuteAction(sources, entries, tags, Pf2eAction.cost.transformTextFrom(rootNode, ", ", this), Pf2eAction.trigger.transformTextFrom(rootNode, ", ", this), Field.alias.replaceTextFromList(rootNode, this), - collectTraitsFrom(rootNode, tags), + traits, Pf2eAction.prerequisites.transformTextFrom(rootNode, ", ", this), Field.requirements.replaceTextFrom(rootNode, this), Pf2eAction.frequency.getFrequencyFrom(rootNode, this), diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteAffliction.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteAffliction.java index 86ceeb892..066cccba9 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteAffliction.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteAffliction.java @@ -4,7 +4,6 @@ import static dev.ebullient.convert.StringUtil.toTitleCase; import java.util.ArrayList; -import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -12,11 +11,9 @@ import java.util.Optional; import java.util.function.Predicate; import java.util.stream.Collectors; - import com.fasterxml.jackson.databind.JsonNode; import dev.ebullient.convert.StringUtil; -import dev.ebullient.convert.tools.Tags; import dev.ebullient.convert.tools.pf2e.qute.QuteAffliction; public class Json2QuteAffliction extends Json2QuteBase { @@ -111,11 +108,8 @@ private static QuteAffliction createAffliction(Json2QuteAffliction convert) { } JsonNode dataNode = nestedAfflictionNode.orElse(node); - Tags tags = new Tags(convert.sources); - Collection<String> traits = convert.collectTraitsFrom(node, tags); - Optional<String> afflictionLevel = level.intFrom(node).map(Objects::toString); - afflictionLevel.ifPresent(lv -> tags.add("affliction", "level", lv)); + afflictionLevel.ifPresent(lv -> convert.tags.add("affliction", "level", lv)); String temptedCurseText = temptedCurse.transformTextFrom(node, "\n", convert); Optional<String> afflictionType = type.getTextFrom(node) @@ -123,9 +117,9 @@ private static QuteAffliction createAffliction(Json2QuteAffliction convert) { .filter(StringUtil::isPresent); afflictionType.ifPresent(type -> { if (isPresent(temptedCurseText)) { - tags.add("affliction", type, "tempted"); + convert.tags.add("affliction", type, "tempted"); } else { - tags.add("affliction", type); + convert.tags.add("affliction", type); } }); @@ -144,8 +138,8 @@ private static QuteAffliction createAffliction(Json2QuteAffliction convert) { ArrayList<String>::new, (acc, n) -> convert.appendToText(acc, n, "##"), ArrayList::addAll), - tags, - traits, + convert.tags, + convert.traits, Field.alias.replaceTextFromList(dataNode, convert), // Level may be e.g. "varies" afflictionLevel.or(() -> level.getTextFrom(node)) diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteArchetype.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteArchetype.java index 700957e43..cffc2418b 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteArchetype.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteArchetype.java @@ -6,10 +6,8 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; - import com.fasterxml.jackson.databind.JsonNode; -import dev.ebullient.convert.tools.Tags; import dev.ebullient.convert.tools.pf2e.qute.QuteArchetype; import dev.ebullient.convert.tools.pf2e.qute.QuteFeat; @@ -21,18 +19,12 @@ public Json2QuteArchetype(Pf2eIndex index, JsonNode rootNode) { @Override protected QuteArchetype buildQuteResource() { - Tags tags = new Tags(sources); - List<String> text = new ArrayList<>(); - - appendToText(text, SourceField.entries.getFrom(rootNode), "##"); - List<String> benefits = ArchetypeField.benefits.getListOfStrings(rootNode, tui()); benefits.forEach(b -> tags.add("archetype", "benefit", b)); int dedicationLevel = ArchetypeField.dedicationLevel.intOrDefault(rootNode, 2); - return new QuteArchetype(sources, text, tags, - collectTraitsFrom(rootNode, tags), + return new QuteArchetype(sources, entries, tags, traits, dedicationLevel, benefits, getFeatures(dedicationLevel)); diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteBackground.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteBackground.java index 761ce44f5..1a1aa61a5 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteBackground.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteBackground.java @@ -1,11 +1,7 @@ package dev.ebullient.convert.tools.pf2e; -import java.util.ArrayList; -import java.util.List; - import com.fasterxml.jackson.databind.JsonNode; -import dev.ebullient.convert.tools.Tags; import dev.ebullient.convert.tools.pf2e.qute.QuteBackground; public class Json2QuteBackground extends Json2QuteBase { @@ -16,11 +12,6 @@ public Json2QuteBackground(Pf2eIndex index, JsonNode rootNode) { @Override protected QuteBackground buildQuteResource() { - Tags tags = new Tags(sources); - List<String> text = new ArrayList<>(); - - appendToText(text, SourceField.entries.getFrom(rootNode), "##"); - Pf2eBackground.boosts.getListOfStrings(rootNode, tui()) .stream() .filter(b -> !b.equalsIgnoreCase("Free")) @@ -32,7 +23,7 @@ protected QuteBackground buildQuteResource() { Pf2eBackground.feat.getListOfStrings(rootNode, tui()) .forEach(s -> tags.add("background", "feat", s)); - return new QuteBackground(sources, text, tags); + return new QuteBackground(sources, entries, tags); } enum Pf2eBackground implements Pf2eJsonNodeReader { diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteBase.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteBase.java index fc5b2e2d6..7f618ec6e 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteBase.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteBase.java @@ -1,7 +1,11 @@ package dev.ebullient.convert.tools.pf2e; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; import com.fasterxml.jackson.databind.JsonNode; +import dev.ebullient.convert.tools.Tags; import dev.ebullient.convert.tools.pf2e.qute.Pf2eQuteBase; import dev.ebullient.convert.tools.pf2e.qute.Pf2eQuteNote; @@ -10,6 +14,9 @@ public abstract class Json2QuteBase implements JsonSource { protected final Pf2eIndexType type; protected final JsonNode rootNode; protected final Pf2eSources sources; + protected final Tags tags; + protected final Set<String> traits; + protected final List<String> entries; public Json2QuteBase(Pf2eIndex index, Pf2eIndexType type, JsonNode rootNode) { this(index, type, rootNode, Pf2eSources.findOrTemporary(type, rootNode)); @@ -20,6 +27,9 @@ public Json2QuteBase(Pf2eIndex index, Pf2eIndexType type, JsonNode rootNode, Pf2 this.type = type; this.rootNode = rootNode; this.sources = sources; + this.tags = new Tags(sources); + this.traits = collectTraitsFrom(rootNode, tags); + this.entries = new ArrayList<>(SourceField.entries.transformListFrom(rootNode, this, "##")); } @Override diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteCreature.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteCreature.java index 019916f32..8125bda66 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteCreature.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteCreature.java @@ -2,17 +2,14 @@ import static dev.ebullient.convert.StringUtil.join; -import java.util.Collection; import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; - import com.fasterxml.jackson.databind.JsonNode; -import dev.ebullient.convert.tools.Tags; import dev.ebullient.convert.tools.pf2e.qute.QuteCreature; import dev.ebullient.convert.tools.pf2e.qute.QuteDataRef; @@ -24,7 +21,7 @@ public Json2QuteCreature(Pf2eIndex index, JsonNode rootNode) { @Override protected QuteCreature buildQuteResource() { - return Pf2eCreature.create(rootNode, this); + return Pf2eCreature.create(this); } /** @@ -84,15 +81,11 @@ enum Pf2eCreature implements Pf2eJsonNodeReader { std, traits; - private static QuteCreature create(JsonNode node, JsonSource convert) { - Tags tags = new Tags(convert.getSources()); - Collection<String> traits = convert.collectTraitsFrom(node, tags); - traits.addAll(alignment.getAlignmentsFrom(node, convert)); + private static QuteCreature create(Json2QuteCreature convert) { + JsonNode node = convert.rootNode; + convert.traits.addAll(alignment.getAlignmentsFrom(node, convert)); - return new QuteCreature(convert.getSources(), - entries.transformTextFrom(node, "\n", convert, "##"), - tags, - traits, + return new QuteCreature(convert.sources, convert.entries, convert.tags, convert.traits, alias.replaceTextFromList(node, convert), description.replaceTextFrom(node, convert), level.intOrNull(node), diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteDeity.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteDeity.java index d1ca0ba0a..b0408f205 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteDeity.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteDeity.java @@ -6,7 +6,6 @@ import static dev.ebullient.convert.StringUtil.toOrdinal; import static dev.ebullient.convert.StringUtil.toTitleCase; -import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; @@ -18,7 +17,6 @@ import dev.ebullient.convert.StringUtil; import dev.ebullient.convert.io.Tui; import dev.ebullient.convert.qute.NamedText; -import dev.ebullient.convert.tools.Tags; import dev.ebullient.convert.tools.pf2e.Pf2eJsonNodeReader.Pf2eAttack; import dev.ebullient.convert.tools.pf2e.qute.QuteDataActivity.Activity; import dev.ebullient.convert.tools.pf2e.qute.QuteDeity; @@ -34,20 +32,15 @@ public Json2QuteDeity(Pf2eIndex index, JsonNode rootNode) { @Override protected QuteDeity buildQuteResource() { - List<String> text = new ArrayList<>(); - Tags tags = new Tags(sources); - Pf2eDeity.domains.getListOfStrings(rootNode, tui()).forEach(d -> tags.add("domain", d, "deity")); Pf2eDeity.alternateDomains.getListOfStrings(rootNode, tui()).forEach(d -> tags.add("domain", d, "deity")); String category = Pf2eDeity.category.getTextOrDefault(rootNode, "Deity"); tags.add("deity", category); - appendToText(text, SourceField.entries.getFrom(rootNode), "##"); - JsonNode alignNode = Pf2eDeity.alignment.getFrom(rootNode); - return new QuteDeity(sources, text, tags, + return new QuteDeity(sources, entries, tags, Field.alias.replaceTextFromList(rootNode, this), category, join(", ", Pf2eDeity.pantheon.linkifyListFrom(rootNode, Pf2eIndexType.deity, this)), @@ -57,7 +50,7 @@ protected QuteDeity buildQuteResource() { commandmentToString(Pf2eDeity.edict.replaceTextFromList(rootNode, this)), commandmentToString(Pf2eDeity.anathema.replaceTextFromList(rootNode, this)), buildCleric(), - buildAvatar(tags), + buildAvatar(), buildIntercession()); } @@ -114,7 +107,7 @@ QuteDeity.QuteDeityCleric buildCleric() { return cleric; } - QuteDeity.QuteDivineAvatar buildAvatar(Tags tags) { + QuteDeity.QuteDivineAvatar buildAvatar() { JsonNode avatarNode = Pf2eDeity.avatar.getFrom(rootNode); if (avatarNode == null) { return null; @@ -154,7 +147,7 @@ QuteDeity.QuteDivineAvatar buildAvatar(Tags tags) { avatar.attacks = Stream.concat( Pf2eDeity.melee.streamFrom(avatarNode).map(n -> Map.entry(n, AttackRangeType.MELEE)), Pf2eDeity.ranged.streamFrom(avatarNode).map(n -> Map.entry(n, AttackRangeType.RANGED))) - .map(e -> buildAvatarAttack(e.getKey(), tags, e.getValue())) + .map(e -> buildAvatarAttack(e.getKey(), e.getValue())) .toList(); avatar.ability = Pf2eDeity.ability.streamFrom(avatarNode) .map(this::buildAvatarAbility) @@ -169,7 +162,7 @@ private NamedText buildAvatarAbility(JsonNode abilityNode) { SourceField.entries.transformTextFrom(abilityNode, "; ", this)); } - private QuteInlineAttack buildAvatarAttack(JsonNode actionNode, Tags tags, AttackRangeType rangeType) { + private QuteInlineAttack buildAvatarAttack(JsonNode actionNode, AttackRangeType rangeType) { Collection<String> traits = collectTraitsFrom(actionNode, tags); traits.addAll(Pf2eDeity.preciousMetal.getListOfStrings(actionNode, tui())); Pf2eDeity.traitNote.getTextFrom(actionNode).ifPresent(traits::add); diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteFeat.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteFeat.java index 0319aa121..01b6bcf5d 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteFeat.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteFeat.java @@ -1,10 +1,8 @@ package dev.ebullient.convert.tools.pf2e; -import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; - import com.fasterxml.jackson.databind.JsonNode; import dev.ebullient.convert.tools.pf2e.qute.QuteFeat; @@ -17,18 +15,12 @@ public Json2QuteFeat(Pf2eIndex index, JsonNode rootNode) { @Override protected QuteFeat buildQuteResource() { - Tags tags = new Tags(sources); - List<String> text = new ArrayList<>(); - - appendToText(text, SourceField.entries.getFrom(rootNode), "##"); - List<String> leadsTo = Pf2eFeat.leadsTo.getListOfStrings(rootNode, tui()) .stream() .map(x -> linkify(Pf2eIndexType.feat, x)) .collect(Collectors.toList()); - return new QuteFeat(sources, text, tags, - collectTraitsFrom(rootNode, tags), + return new QuteFeat(sources, entries, tags, traits, Field.alias.replaceTextFromList(rootNode, this), Pf2eFeat.level.getTextOrDefault(rootNode, "1"), Pf2eFeat.access.transformTextFrom(rootNode, ", ", this), @@ -44,8 +36,6 @@ protected QuteFeat buildQuteResource() { public QuteFeat buildArchetype(String archetypeName, String dedicationLevel) { String featLevel = Pf2eFeat.level.getTextOrDefault(rootNode, "1"); - List<String> text = new ArrayList<>(); - Tags tags = new Tags(); String note = null; if (!Objects.equals(dedicationLevel, featLevel)) { @@ -55,10 +45,7 @@ public QuteFeat buildArchetype(String archetypeName, String dedicationLevel) { archetypeName); } - appendToText(text, SourceField.entries.getFrom(rootNode), "##"); - - return new QuteFeat(sources, text, tags, - collectTraitsFrom(rootNode, tags), + return new QuteFeat(sources, entries, tags, traits, List.of(), dedicationLevel, Pf2eFeat.access.transformTextFrom(rootNode, ", ", this), diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteHazard.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteHazard.java index 6488320e8..e00910f5e 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteHazard.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteHazard.java @@ -1,11 +1,8 @@ package dev.ebullient.convert.tools.pf2e; -import java.util.ArrayList; -import java.util.List; import com.fasterxml.jackson.databind.JsonNode; import dev.ebullient.convert.tools.JsonTextConverter; -import dev.ebullient.convert.tools.Tags; import dev.ebullient.convert.tools.pf2e.qute.QuteDataGenericStat; import dev.ebullient.convert.tools.pf2e.qute.QuteHazard; @@ -17,13 +14,9 @@ public Json2QuteHazard(Pf2eIndex index, JsonNode rootNode) { @Override protected QuteHazard buildQuteResource() { - Tags tags = new Tags(sources); - List<String> text = new ArrayList<>(); + entries.addAll(Pf2eHazard.description.transformListFrom(rootNode, this, "##")); - appendToText(text, Pf2eHazard.description.getFrom(rootNode), "##"); - - return new QuteHazard(sources, text, tags, - collectTraitsFrom(rootNode, tags), + return new QuteHazard(sources, entries, tags, traits, Pf2eHazard.level.getTextOrDefault(rootNode, "0"), Pf2eHazard.disable.transformTextFrom(rootNode, "\n", index), Pf2eHazard.reset.transformTextFrom(rootNode, "\n", index), diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteItem.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteItem.java index 39750df07..6f328016e 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteItem.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteItem.java @@ -8,9 +8,7 @@ import java.util.Collection; import java.util.List; import java.util.Map.Entry; -import java.util.Set; import java.util.stream.Collectors; - import com.fasterxml.jackson.databind.JsonNode; import dev.ebullient.convert.qute.NamedText; @@ -35,18 +33,12 @@ public Json2QuteItem(Pf2eIndex index, JsonNode rootNode) { @Override protected Pf2eQuteBase buildQuteResource() { - Tags tags = new Tags(sources); - List<String> text = new ArrayList<>(); - List<String> aliases = new ArrayList<>(Field.alias.replaceTextFromList(rootNode, this)); - Set<String> traits = collectTraitsFrom(rootNode, tags); - - appendToText(text, SourceField.entries.getFrom(rootNode), "##"); - String duration = Pf2eItem.duration.existsIn(rootNode) ? SourceField.entry.getTextOrEmpty(Pf2eItem.duration.getFrom(rootNode)) : null; - return new QuteItem(sources, text, tags, traits, aliases, + return new QuteItem(sources, entries, tags, traits, + Field.alias.replaceTextFromList(rootNode, this), buildActivate(), getPrice(rootNode), join(", ", Pf2eItem.ammunition.linkifyListFrom(rootNode, Pf2eIndexType.item, this)), @@ -54,15 +46,15 @@ protected Pf2eQuteBase buildQuteResource() { Pf2eItem.onset.transformTextFrom(rootNode, ", ", this), replaceText(Pf2eItem.access.getTextOrEmpty(rootNode)), duration, - getCategory(tags), + getCategory(), linkify(Pf2eIndexType.group, getGroup()), Pf2eItem.hands.getTextOrEmpty(rootNode), keysToList(List.of(Pf2eItem.usage, Pf2eItem.bulk)), - getContract(tags), + getContract(), getShieldData(), getArmorData(), - getWeaponData(tags), - getVariants(tags), + getWeaponData(), + getVariants(), Pf2eItem.craftReq.transformTextFrom(rootNode, "; ", this)); } @@ -136,7 +128,7 @@ private QuteItemArmorData getArmorData() { return armorData; } - private List<QuteItemWeaponData> getWeaponData(Tags tags) { + private List<QuteItemWeaponData> getWeaponData() { JsonNode weaponDataNode = Pf2eItem.weaponData.getFrom(rootNode); if (weaponDataNode == null) { return null; @@ -152,7 +144,7 @@ private List<QuteItemWeaponData> getWeaponData(Tags tags) { return weaponDataList; } - private List<QuteItem.QuteItemVariant> getVariants(Tags tags) { + private List<QuteItem.QuteItemVariant> getVariants() { JsonNode variantsNode = Pf2eItem.variants.getFrom(rootNode); if (variantsNode == null) @@ -176,7 +168,7 @@ private List<QuteItem.QuteItemVariant> getVariants(Tags tags) { return variantList; } - private Collection<NamedText> getContract(Tags tags) { + private Collection<NamedText> getContract() { JsonNode contractNode = Pf2eItem.contract.getFrom(rootNode); if (contractNode == null) { return null; @@ -241,7 +233,7 @@ private String getGroup() { return Pf2eWeaponData.group.getTextOrEmpty(rootNode); } - String getCategory(Tags tags) { + String getCategory() { String category = Pf2eItem.category.getTextOrEmpty(rootNode); String subcategory = Pf2eItem.subCategory.getTextOrEmpty(rootNode); if (category == null) { diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteRitual.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteRitual.java index 5a0a13729..3b51a52b1 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteRitual.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteRitual.java @@ -2,13 +2,10 @@ import static dev.ebullient.convert.StringUtil.joinConjunct; -import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; - import com.fasterxml.jackson.databind.JsonNode; -import dev.ebullient.convert.tools.Tags; import dev.ebullient.convert.tools.pf2e.qute.Pf2eQuteBase; import dev.ebullient.convert.tools.pf2e.qute.QuteDataRange; import dev.ebullient.convert.tools.pf2e.qute.QuteRitual; @@ -26,27 +23,22 @@ public Json2QuteRitual(Pf2eIndex index, JsonNode rootNode) { @Override protected Pf2eQuteBase buildQuteResource() { - Tags tags = new Tags(sources); - List<String> text = new ArrayList<>(); - - appendToText(text, SourceField.entries.getFrom(rootNode), "##"); - String level = Pf2eSpell.level.getTextOrDefault(rootNode, "1"); tags.add(RITUAL_TAG, level); - return new QuteRitual(sources, text, tags, + return new QuteRitual(sources, entries, tags, level, "Ritual", - collectTraitsFrom(rootNode, tags), + traits, Field.alias.replaceTextFromList(rootNode, this), getQuteRitualCast(), getQuteRitualChecks(), - getQuteRitualSpellTarget(tags), + getQuteRitualSpellTarget(), Field.requirements.transformTextFrom(rootNode, ", ", this), null, getHeightenedCast()); } - QuteSpellTarget getQuteRitualSpellTarget(Tags tags) { + QuteSpellTarget getQuteRitualSpellTarget() { String targets = replaceText(Pf2eSpell.targets.getTextOrEmpty(rootNode)); QuteDataRange range = Pf2eSpell.range.getRangeFrom(rootNode, this); SpellArea area = Pf2eSpell.area.fieldFromTo(rootNode, SpellArea.class, tui()); diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteSpell.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteSpell.java index 6a8b4d646..e70b6d3bc 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteSpell.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteSpell.java @@ -11,12 +11,10 @@ import java.util.Map.Entry; import java.util.Objects; import java.util.stream.Stream; - import com.fasterxml.jackson.databind.JsonNode; import dev.ebullient.convert.qute.NamedText; import dev.ebullient.convert.tools.JsonNodeReader.FieldValue; -import dev.ebullient.convert.tools.Tags; import dev.ebullient.convert.tools.pf2e.qute.Pf2eQuteBase; import dev.ebullient.convert.tools.pf2e.qute.QuteDataDuration; import dev.ebullient.convert.tools.pf2e.qute.QuteDataRange; @@ -41,13 +39,6 @@ protected Json2QuteSpell(Pf2eIndex index, Pf2eIndexType type, JsonNode rootNode) @Override protected Pf2eQuteBase buildQuteResource() { - Tags tags = new Tags(sources); - List<String> text = new ArrayList<>(); - - appendToText(text, SourceField.entries.getFrom(rootNode), "##"); - - Collection<String> traits = collectTraitsFrom(rootNode, tags); - boolean focus = Pf2eSpell.focus.booleanOrDefault(rootNode, false); String level = Pf2eSpell.level.getTextOrDefault(rootNode, "1"); String type = "spell"; @@ -91,7 +82,7 @@ protected Pf2eQuteBase buildQuteResource() { components.stream().map(Pf2eSpellComponent::getAddedTrait) .distinct().map(this::linkifyTrait).forEach(traits::add); - return new QuteSpell(sources, text, tags, + return new QuteSpell(sources, entries, tags, level, toTitleCase(type), traits, Field.alias.replaceTextFromList(rootNode, this), @@ -100,7 +91,7 @@ level, toTitleCase(type), Pf2eSpell.cost.transformTextFrom(rootNode, ", ", this), Pf2eSpell.trigger.transformTextFrom(rootNode, ", ", this), Pf2eSpell.requirements.transformTextFrom(rootNode, ", ", this), - getQuteSpellTarget(tags), + getQuteSpellTarget(), Pf2eSpell.savingThrow.getSpellSaveFrom(rootNode, this), Pf2eSpell.duration.getSpellDurationFrom(rootNode, this), Pf2eSpell.domains.linkifyListFrom(rootNode, Pf2eIndexType.domain, this), @@ -111,7 +102,7 @@ level, toTitleCase(type), getAmpEffects()); } - QuteSpellTarget getQuteSpellTarget(Tags tags) { + QuteSpellTarget getQuteSpellTarget() { String targets = Pf2eSpell.targets.replaceTextFrom(rootNode, this); SpellArea area = Pf2eSpell.area.fieldFromTo(rootNode, SpellArea.class, tui()); QuteDataRange range = Pf2eSpell.range.getRangeFrom(rootNode, this); diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteTable.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteTable.java index eaac32255..87446a3bc 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteTable.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteTable.java @@ -4,11 +4,9 @@ import java.util.ArrayList; import java.util.List; - import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; -import dev.ebullient.convert.tools.Tags; import dev.ebullient.convert.tools.pf2e.qute.Pf2eQuteNote; public class Json2QuteTable extends Json2QuteBase { @@ -19,9 +17,7 @@ public Json2QuteTable(Pf2eIndex index, JsonNode rootNode) { @Override protected Pf2eQuteNote buildQuteNote() { - Tags tags = new Tags(sources); List<String> text = new ArrayList<>(); - ((ObjectNode) rootNode).put(SourceField.type.name(), "table"); appendToText(text, rootNode, null); diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteTrait.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteTrait.java index f867a587e..4a7a2a955 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteTrait.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteTrait.java @@ -2,10 +2,8 @@ import java.util.ArrayList; import java.util.List; - import com.fasterxml.jackson.databind.JsonNode; -import dev.ebullient.convert.tools.Tags; import dev.ebullient.convert.tools.pf2e.qute.Pf2eQuteNote; import dev.ebullient.convert.tools.pf2e.qute.QuteTrait; import dev.ebullient.convert.tools.pf2e.qute.QuteTraitIndex; @@ -18,8 +16,6 @@ public Json2QuteTrait(Pf2eIndex index, JsonNode rootNode) { @Override protected QuteTrait buildQuteResource() { - Tags tags = new Tags(sources); - List<String> text = new ArrayList<>(); List<String> categories = new ArrayList<>(); Field.categories.getListOfStrings(rootNode, tui()).forEach(c -> { @@ -28,7 +24,7 @@ protected QuteTrait buildQuteResource() { JsonNode implied = TraitField.implies.getFrom(rootNode); if (implied != null) { implied.fieldNames().forEachRemaining(n -> { - if ("spell".equals(n.toLowerCase())) { + if ("spell".equalsIgnoreCase(n)) { String school = implied.get(n).get("_fSchool").asText(); tags.add("trait", "category", "spell", school); categories.add(String.format("%s (%s)", c, school)); @@ -41,9 +37,7 @@ protected QuteTrait buildQuteResource() { } }); - appendToText(text, SourceField.entries.getFrom(rootNode), "##"); - - return new QuteTrait(sources, text, tags, List.of(), categories); + return new QuteTrait(sources, entries, tags, List.of(), categories); } static Pf2eQuteNote buildIndex(Pf2eIndex index) { diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAbility.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAbility.java index b26591dd3..ccaec6b86 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAbility.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAbility.java @@ -65,7 +65,7 @@ public final class QuteAbility extends Pf2eQuteNote implements QuteUtil.Renderab // Internal only. private final JsonSource _converter; - public QuteAbility(Pf2eSources sources, String name, String reference, String text, Tags tags, + public QuteAbility(Pf2eSources sources, String name, String reference, List<String> text, Tags tags, Collection<String> traits, QuteDataActivity activity, QuteDataRange range, List<String> components, String requirements, String prerequisites, String cost, String trigger, QuteDataFrequency frequency, String special, String note, diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteCreature.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteCreature.java index 801c0d464..cd95ec266 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteCreature.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteCreature.java @@ -68,7 +68,7 @@ public class QuteCreature extends Pf2eQuteBase { public final List<CreatureRitualCasting> ritualCasting; public QuteCreature( - Pf2eSources sources, String text, Tags tags, + Pf2eSources sources, List<String> text, Tags tags, Collection<String> traits, List<String> aliases, String description, Integer level, Integer perception, QuteDataDefenses defenses, CreatureLanguages languages, CreatureSkills skills, From 36973d015d5e7dde56bb4a0f4f957b9a7217fd24 Mon Sep 17 00:00:00 2001 From: miscoined <miscoined@gmail.com> Date: Mon, 8 Jul 2024 02:58:58 +1000 Subject: [PATCH 11/25] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Move=20collectTraits?= =?UTF-8?q?From=20into=20JsonTextReplacement?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fits better with the other methods defined in that class rather than the recursive parse methods in JsonSource --- .../convert/tools/pf2e/JsonSource.java | 18 ---------------- .../tools/pf2e/JsonTextReplacement.java | 21 ++++++++++++++++++- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java b/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java index d4a9e1353..56be04410 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java @@ -5,8 +5,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Set; -import java.util.TreeSet; import java.util.stream.Collectors; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; @@ -23,22 +21,6 @@ public interface JsonSource extends JsonTextReplacement { - /** - * Collect and linkify traits from the specified node. - * - * @param tags The tags to populate while collecting traits. If null, then don't populate any tags. - * - * @return an empty or sorted/linkified list of traits (never null) - */ - default Set<String> collectTraitsFrom(JsonNode sourceNode, Tags tags) { - return Field.traits.getListOfStrings(sourceNode, tui()).stream() - .peek(tags == null ? t -> { - } : t -> tags.add("trait", t)) - .sorted() - .map(s -> linkify(Pf2eIndexType.trait, s)) - .collect(Collectors.toCollection(TreeSet::new)); - } - /** * External (and recursive) entry point for content parsing. * diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/JsonTextReplacement.java b/src/main/java/dev/ebullient/convert/tools/pf2e/JsonTextReplacement.java index 03ff7793a..24104ea72 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/JsonTextReplacement.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/JsonTextReplacement.java @@ -7,9 +7,11 @@ import java.util.ArrayList; import java.util.List; +import java.util.Set; +import java.util.TreeSet; import java.util.regex.MatchResult; import java.util.regex.Pattern; - +import java.util.stream.Collectors; import com.fasterxml.jackson.databind.JsonNode; import dev.ebullient.convert.config.CompendiumConfig; @@ -18,6 +20,7 @@ import dev.ebullient.convert.tools.JsonNodeReader; import dev.ebullient.convert.tools.JsonNodeReader.FieldValue; import dev.ebullient.convert.tools.JsonTextConverter; +import dev.ebullient.convert.tools.Tags; import dev.ebullient.convert.tools.pf2e.qute.QuteDataActivity.Activity; public interface JsonTextReplacement extends JsonTextConverter<Pf2eIndexType> { @@ -206,6 +209,22 @@ default String replaceActionAs(MatchResult match) { return linkifyActivity(type, index().rulesVaultRoot()); } + /** + * Collect and linkify traits from the specified node. + * + * @param tags The tags to populate while collecting traits. If null, then don't populate any tags. + * + * @return an empty or sorted/linkified list of traits (never null) + */ + default Set<String> collectTraitsFrom(JsonNode sourceNode, Tags tags) { + return Field.traits.getListOfStrings(sourceNode, tui()).stream() + .peek(tags == null ? t -> { + } : t -> tags.add("trait", t)) + .sorted() + .map(s -> linkify(Pf2eIndexType.trait, s)) + .collect(Collectors.toCollection(TreeSet::new)); + } + default String linkifyRuneItem(MatchResult match) { String[] parts = match.group(1).split("\\|"); String linkText = parts[0]; From 770412e319b5cdd437118306c312279e949b5bf8 Mon Sep 17 00:00:00 2001 From: miscoined <miscoined@gmail.com> Date: Mon, 8 Jul 2024 11:07:59 +1000 Subject: [PATCH 12/25] =?UTF-8?q?=F0=9F=9A=B8=F0=9F=94=A5=20Make=20traits?= =?UTF-8?q?=20a=20collection=20of=20QuteDataRef?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 🚸 Allows template authors to access trait reference data directly rather than just the markdown doc. - 🚸 Incidentally fixes trait ordering so that it's alphabetically by trait name, rather than by whether or not there's a link. - 🔥 Remove alignment field handling for creature nodes - it was never used in the data --- .../ebullient/convert/tools/pf2e/Json2QuteBase.java | 3 ++- .../convert/tools/pf2e/Json2QuteCreature.java | 6 ++---- .../ebullient/convert/tools/pf2e/Json2QuteDeity.java | 7 ++++--- .../ebullient/convert/tools/pf2e/Json2QuteSpell.java | 3 ++- .../dev/ebullient/convert/tools/pf2e/JsonSource.java | 3 ++- .../convert/tools/pf2e/JsonTextReplacement.java | 10 +++++----- .../convert/tools/pf2e/Pf2eJsonNodeReader.java | 6 ++++-- .../ebullient/convert/tools/pf2e/qute/QuteAbility.java | 10 +++++----- .../ebullient/convert/tools/pf2e/qute/QuteAction.java | 6 +++--- .../convert/tools/pf2e/qute/QuteAffliction.java | 6 +++--- .../convert/tools/pf2e/qute/QuteArchetype.java | 6 +++--- .../convert/tools/pf2e/qute/QuteCreature.java | 6 +++--- .../ebullient/convert/tools/pf2e/qute/QuteFeat.java | 6 +++--- .../ebullient/convert/tools/pf2e/qute/QuteHazard.java | 8 ++++---- .../convert/tools/pf2e/qute/QuteInlineAttack.java | 8 ++++---- .../ebullient/convert/tools/pf2e/qute/QuteItem.java | 10 +++++----- .../ebullient/convert/tools/pf2e/qute/QuteRitual.java | 6 +++--- .../ebullient/convert/tools/pf2e/qute/QuteSpell.java | 6 +++--- 18 files changed, 60 insertions(+), 56 deletions(-) diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteBase.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteBase.java index 7f618ec6e..f8972d50b 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteBase.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteBase.java @@ -8,6 +8,7 @@ import dev.ebullient.convert.tools.Tags; import dev.ebullient.convert.tools.pf2e.qute.Pf2eQuteBase; import dev.ebullient.convert.tools.pf2e.qute.Pf2eQuteNote; +import dev.ebullient.convert.tools.pf2e.qute.QuteDataRef; public abstract class Json2QuteBase implements JsonSource { protected final Pf2eIndex index; @@ -15,7 +16,7 @@ public abstract class Json2QuteBase implements JsonSource { protected final JsonNode rootNode; protected final Pf2eSources sources; protected final Tags tags; - protected final Set<String> traits; + protected final Set<QuteDataRef> traits; protected final List<String> entries; public Json2QuteBase(Pf2eIndex index, Pf2eIndexType type, JsonNode rootNode) { diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteCreature.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteCreature.java index 8125bda66..918638f97 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteCreature.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteCreature.java @@ -57,14 +57,14 @@ protected QuteCreature buildQuteResource() { enum Pf2eCreature implements Pf2eJsonNodeReader { abilities, abilityMods, - alignment, + alignment, // unused in the data but defined in the schema alias, attacks, defenses, description, entries, hasImages, - inflicts, // not actually present in any of the entries + inflicts, // unused in the data but defined in the schema isNpc, items, languages, @@ -83,8 +83,6 @@ enum Pf2eCreature implements Pf2eJsonNodeReader { private static QuteCreature create(Json2QuteCreature convert) { JsonNode node = convert.rootNode; - convert.traits.addAll(alignment.getAlignmentsFrom(node, convert)); - return new QuteCreature(convert.sources, convert.entries, convert.tags, convert.traits, alias.replaceTextFromList(node, convert), description.replaceTextFrom(node, convert), diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteDeity.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteDeity.java index b0408f205..1c681a046 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteDeity.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteDeity.java @@ -19,6 +19,7 @@ import dev.ebullient.convert.qute.NamedText; import dev.ebullient.convert.tools.pf2e.Pf2eJsonNodeReader.Pf2eAttack; import dev.ebullient.convert.tools.pf2e.qute.QuteDataActivity.Activity; +import dev.ebullient.convert.tools.pf2e.qute.QuteDataRef; import dev.ebullient.convert.tools.pf2e.qute.QuteDeity; import dev.ebullient.convert.tools.pf2e.qute.QuteInlineAttack; import dev.ebullient.convert.tools.pf2e.qute.QuteInlineAttack.AttackRangeType; @@ -163,9 +164,9 @@ private NamedText buildAvatarAbility(JsonNode abilityNode) { } private QuteInlineAttack buildAvatarAttack(JsonNode actionNode, AttackRangeType rangeType) { - Collection<String> traits = collectTraitsFrom(actionNode, tags); - traits.addAll(Pf2eDeity.preciousMetal.getListOfStrings(actionNode, tui())); - Pf2eDeity.traitNote.getTextFrom(actionNode).ifPresent(traits::add); + Collection<QuteDataRef> traits = collectTraitsFrom(actionNode, tags); + Pf2eDeity.preciousMetal.getListOfStrings(actionNode, tui()).stream().map(QuteDataRef::new).forEach(traits::add); + Pf2eDeity.traitNote.getTextFrom(actionNode).map(QuteDataRef::new).ifPresent(traits::add); return new QuteInlineAttack( Pf2eAttack.name.getTextOrDefault(actionNode, "attack"), diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteSpell.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteSpell.java index e70b6d3bc..349d879d5 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteSpell.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteSpell.java @@ -18,6 +18,7 @@ import dev.ebullient.convert.tools.pf2e.qute.Pf2eQuteBase; import dev.ebullient.convert.tools.pf2e.qute.QuteDataDuration; import dev.ebullient.convert.tools.pf2e.qute.QuteDataRange; +import dev.ebullient.convert.tools.pf2e.qute.QuteDataRef; import dev.ebullient.convert.tools.pf2e.qute.QuteDataTimedDuration; import dev.ebullient.convert.tools.pf2e.qute.QuteSpell; import dev.ebullient.convert.tools.pf2e.qute.QuteSpell.QuteSpellAmp; @@ -80,7 +81,7 @@ protected Pf2eQuteBase buildQuteResource() { List<Pf2eSpellComponent> components = Pf2eSpell.components.getComponentsFrom(rootNode, this); // Add additional traits according to present components components.stream().map(Pf2eSpellComponent::getAddedTrait) - .distinct().map(this::linkifyTrait).forEach(traits::add); + .distinct().map(this::linkifyTrait).map(QuteDataRef::fromMarkdownLink).forEach(traits::add); return new QuteSpell(sources, entries, tags, level, toTitleCase(type), diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java b/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java index 56be04410..0229c2b4d 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java @@ -18,6 +18,7 @@ import dev.ebullient.convert.tools.pf2e.Json2QuteItem.Pf2eItem; import dev.ebullient.convert.tools.pf2e.qute.Pf2eQuteBase; import dev.ebullient.convert.tools.pf2e.qute.QuteDataActivity; +import dev.ebullient.convert.tools.pf2e.qute.QuteDataRef; public interface JsonSource extends JsonTextReplacement { @@ -585,7 +586,7 @@ default List<String> embedGenericData(String tag, JsonNode data) { // Add traits Tags tags = new Tags(); - Collection<String> traits = collectTraitsFrom(data, tags); + Collection<QuteDataRef> traits = collectTraitsFrom(data, tags); text.add(join(" ", traits) + " "); maybeAddBlankLine(text); diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/JsonTextReplacement.java b/src/main/java/dev/ebullient/convert/tools/pf2e/JsonTextReplacement.java index 24104ea72..f722b3db2 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/JsonTextReplacement.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/JsonTextReplacement.java @@ -22,9 +22,9 @@ import dev.ebullient.convert.tools.JsonTextConverter; import dev.ebullient.convert.tools.Tags; import dev.ebullient.convert.tools.pf2e.qute.QuteDataActivity.Activity; +import dev.ebullient.convert.tools.pf2e.qute.QuteDataRef; public interface JsonTextReplacement extends JsonTextConverter<Pf2eIndexType> { - enum Field implements Pf2eJsonNodeReader { alias, auto, @@ -214,14 +214,14 @@ default String replaceActionAs(MatchResult match) { * * @param tags The tags to populate while collecting traits. If null, then don't populate any tags. * - * @return an empty or sorted/linkified list of traits (never null) + * @return a set of {@link QuteDataRef}s to trait notes, or an empty set (never null) */ - default Set<String> collectTraitsFrom(JsonNode sourceNode, Tags tags) { + default Set<QuteDataRef> collectTraitsFrom(JsonNode sourceNode, Tags tags) { return Field.traits.getListOfStrings(sourceNode, tui()).stream() - .peek(tags == null ? t -> { - } : t -> tags.add("trait", t)) + .peek(tags == null ? (t -> {}) : t -> tags.add("trait", t)) .sorted() .map(s -> linkify(Pf2eIndexType.trait, s)) + .map(QuteDataRef::fromMarkdownLink) .collect(Collectors.toCollection(TreeSet::new)); } diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java index c27140433..43c8550d8 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java @@ -33,6 +33,7 @@ import dev.ebullient.convert.tools.pf2e.qute.QuteDataGenericStat.QuteDataNamedBonus; import dev.ebullient.convert.tools.pf2e.qute.QuteDataHpHardnessBt; import dev.ebullient.convert.tools.pf2e.qute.QuteDataRange; +import dev.ebullient.convert.tools.pf2e.qute.QuteDataRef; import dev.ebullient.convert.tools.pf2e.qute.QuteDataSpeed; import dev.ebullient.convert.tools.pf2e.qute.QuteDataTimedDuration; import dev.ebullient.convert.tools.pf2e.qute.QuteInlineAttack; @@ -47,7 +48,7 @@ public interface Pf2eJsonNodeReader extends JsonNodeReader { default List<String> getAlignmentsFrom(JsonNode alignNode, JsonSource convert) { return streamFrom(alignNode) .map(JsonNode::asText) - .map(a -> a.length() > 2 ? a : convert.linkifyTrait(a.toUpperCase())) + .map(a -> a.length() > 2 ? a : convert.linkify(Pf2eIndexType.trait, a.toUpperCase())) .toList(); } @@ -104,7 +105,7 @@ default List<QuteInlineAttack> getAttacksFrom(JsonNode source, JsonSource conver * traits from these activation components to {@code traits}. Return an empty list if we couldn't get activation * components. */ - default List<String> getActivationComponentsFrom(JsonNode source, Set<String> traits, JsonSource convert) { + default List<String> getActivationComponentsFrom(JsonNode source, Set<QuteDataRef> traits, JsonSource convert) { List<String> rawComponents = getListOfStrings(source, convert.tui()).stream() .map(s -> s.replaceFirst("^\\((%s)\\)$", "\1")) // remove parens .toList(); @@ -122,6 +123,7 @@ default List<String> getActivationComponentsFrom(JsonNode source, Set<String> tr return Stream.of(); }).distinct() .map(convert::linkifyTrait) + .map(QuteDataRef::fromMarkdownLink) .forEach(traits::add); return rawComponents.stream().map(convert::replaceText).toList(); diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAbility.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAbility.java index ccaec6b86..0279d2927 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAbility.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAbility.java @@ -29,10 +29,10 @@ public final class QuteAbility extends Pf2eQuteNote implements QuteUtil.Renderab /** A formatted string which is a link to the base ability that this ability references. Embedded only. */ public final String reference; /** - * Collection of trait links. Use `{#for}` or `{#each}` to iterate over the collection. - * See [traitList](#traitlist) or [bareTraitList](#baretraitlist). + * Collection of trait links as {@link QuteDataRef}. Use `{#for}` or `{#each}` to iterate over the collection. + * See {@link QuteAbility#getBareTraitList()}. */ - public final Collection<String> traits; + public final Collection<QuteDataRef> traits; /** {@link QuteDataRange}. The targeting range for this ability. */ public final QuteDataRange range; /** List of formatted strings. Activation components for this ability, e.g. command, envision */ @@ -66,7 +66,7 @@ public final class QuteAbility extends Pf2eQuteNote implements QuteUtil.Renderab private final JsonSource _converter; public QuteAbility(Pf2eSources sources, String name, String reference, List<String> text, Tags tags, - Collection<String> traits, QuteDataActivity activity, QuteDataRange range, + Collection<QuteDataRef> traits, QuteDataActivity activity, QuteDataRange range, List<String> components, String requirements, String prerequisites, String cost, String trigger, QuteDataFrequency frequency, String special, String note, boolean embedded, JsonSource converter) { @@ -128,7 +128,7 @@ public String getBareTraitList() { return ""; } return traits.stream() - .map(x -> x.replaceAll(" \".*\"", "")) + .map(ref -> new QuteDataRef(ref.displayText(), ref.notePath(), null).toString()) .collect(Collectors.joining(", ")); } diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAction.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAction.java index 7397fe053..f95538f8d 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAction.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAction.java @@ -20,8 +20,8 @@ public class QuteAction extends Pf2eQuteBase { public final String trigger; /** Aliases for this note */ public final List<String> aliases; - /** Collection of traits (decorated links) */ - public final Collection<String> traits; + /** Collection of traits (collection of {@link QuteDataRef}) */ + public final Collection<QuteDataRef> traits; /** Situational requirements for performing this action */ public final String requirements; /** Prerequisite trait or characteristic for performing this action */ @@ -39,7 +39,7 @@ public class QuteAction extends Pf2eQuteBase { public final QuteDataActivity activity; public QuteAction(Pf2eSources sources, List<String> text, Tags tags, - String cost, String trigger, List<String> aliases, Collection<String> traits, + String cost, String trigger, List<String> aliases, Collection<QuteDataRef> traits, String prerequisites, String requirements, QuteDataFrequency frequency, QuteDataActivity activity, ActionType actionType) { super(sources, text, tags); diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAffliction.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAffliction.java index aa3b2660c..35d192f10 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAffliction.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAffliction.java @@ -22,8 +22,8 @@ @TemplateData public final class QuteAffliction extends Pf2eQuteNote implements QuteUtil.Renderable, QuteAbilityOrAffliction { - /** Collection of traits (decorated links) */ - public final Collection<String> traits; + /** Collection of traits ({@link QuteDataRef}) */ + public final Collection<QuteDataRef> traits; /** Integer from 1 to 10. Level of the affliction. */ public final String level; /** Aliases for this note. Only populated if not embedded. */ @@ -58,7 +58,7 @@ public final class QuteAffliction extends Pf2eQuteNote implements QuteUtil.Rende public QuteAffliction( Pf2eSources sources, String name, List<String> text, Tags tags, - Collection<String> traits, List<String> aliases, String level, + Collection<QuteDataRef> traits, List<String> aliases, String level, String category, String maxDuration, String onset, QuteAfflictionSave savingThrow, String effect, String temptedCurse, List<String> notes, Map<String, QuteAfflictionStage> stages, boolean isEmbedded, JsonTextConverter<?> _converter) { diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteArchetype.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteArchetype.java index 53ec98b96..cdcd377ec 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteArchetype.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteArchetype.java @@ -15,15 +15,15 @@ @TemplateData public class QuteArchetype extends Pf2eQuteBase { - /** Collection of traits (decorated links) */ - public final Collection<String> traits; + /** Collection of traits (collection of {@link QuteDataRef}) */ + public final Collection<QuteDataRef> traits; public final int dedicationLevel; public final List<String> benefits; public final List<String> feats; public QuteArchetype(Pf2eSources sources, List<String> text, Tags tags, - Collection<String> traits, int dedicationLevel, List<String> benefits, List<String> feats) { + Collection<QuteDataRef> traits, int dedicationLevel, List<String> benefits, List<String> feats) { super(sources, text, tags); this.traits = traits; diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteCreature.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteCreature.java index cd95ec266..6c931d926 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteCreature.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteCreature.java @@ -28,8 +28,8 @@ public class QuteCreature extends Pf2eQuteBase { /** Aliases for this note (optional) */ public final List<String> aliases; - /** Collection of traits (decorated links, optional) */ - public final Collection<String> traits; + /** Collection of traits (collection of {@link QuteDataRef}) */ + public final Collection<QuteDataRef> traits; /** Short creature description (optional) */ public final String description; /** Creature level (number, optional) */ @@ -69,7 +69,7 @@ public class QuteCreature extends Pf2eQuteBase { public QuteCreature( Pf2eSources sources, List<String> text, Tags tags, - Collection<String> traits, List<String> aliases, + Collection<QuteDataRef> traits, List<String> aliases, String description, Integer level, Integer perception, QuteDataDefenses defenses, CreatureLanguages languages, CreatureSkills skills, List<CreatureSense> senses, Map<String, Integer> abilityMods, diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteFeat.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteFeat.java index fc9f64fe0..1285281ee 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteFeat.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteFeat.java @@ -22,8 +22,8 @@ @TemplateData public class QuteFeat extends Pf2eQuteBase { - /** Collection of traits (decorated links) */ - public final Collection<String> traits; + /** Collection of traits (collection of {@link QuteDataRef}) */ + public final Collection<QuteDataRef> traits; /** Aliases for this note */ public final List<String> aliases; @@ -51,7 +51,7 @@ public class QuteFeat extends Pf2eQuteBase { public final boolean embedded; public QuteFeat(Pf2eSources sources, List<String> text, Tags tags, - Collection<String> traits, List<String> aliases, + Collection<QuteDataRef> traits, List<String> aliases, String level, String access, QuteDataFrequency frequency, QuteDataActivity activity, String trigger, String cost, String requirements, String prerequisites, String special, String note, List<String> leadsTo, boolean embedded) { diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteHazard.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteHazard.java index a869db30c..0035c1def 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteHazard.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteHazard.java @@ -26,8 +26,8 @@ @TemplateData public class QuteHazard extends Pf2eQuteBase { - /** Collection of traits (decorated links) */ - public final Collection<String> traits; + /** Collection of traits (collection of {@link QuteDataRef}) */ + public final Collection<QuteDataRef> traits; public final String level; public final String disable; @@ -83,7 +83,7 @@ public class QuteHazard extends Pf2eQuteBase { public final QuteDataGenericStat perception; public QuteHazard(Pf2eSources sources, List<String> text, Tags tags, - Collection<String> traits, String level, String disable, + Collection<QuteDataRef> traits, String level, String disable, String reset, String routine, QuteDataDefenses defenses, List<QuteInlineAttack> attacks, List<QuteAbility> abilities, List<QuteAbilityOrAffliction> actions, QuteHazardStealth stealth, QuteDataGenericStat perception) { @@ -102,7 +102,7 @@ public QuteHazard(Pf2eSources sources, List<String> text, Tags tags, } public String getComplexity() { - if (traits == null || traits.stream().noneMatch(t -> t.contains("complex"))) { + if (traits == null || traits.stream().noneMatch(ref -> ref.displayText().equalsIgnoreCase("complex"))) { return "Simple"; } return "Complex"; diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteInlineAttack.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteInlineAttack.java index 1078a0e24..69a92705b 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteInlineAttack.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteInlineAttack.java @@ -46,8 +46,8 @@ public final class QuteInlineAttack implements QuteDataGenericStat, QuteUtil.Ren */ public final Collection<String> damageTypes; - /** Any traits associated with the attack (collection of decorated links) */ - public final Collection<String> traits; + /** Any traits associated with the attack (collection of {@link QuteDataRef}) */ + public final Collection<QuteDataRef> traits; /** * Any additional effects associated with the attack e.g. grab (list of strings). Effects listed here @@ -66,7 +66,7 @@ public final class QuteInlineAttack implements QuteDataGenericStat, QuteUtil.Ren public QuteInlineAttack( String name, QuteDataActivity activity, AttackRangeType rangeType, Integer attackBonus, String damage, - Collection<String> damageTypes, Collection<String> traits, List<String> effects, String multilineEffect, + Collection<String> damageTypes, Collection<QuteDataRef> traits, List<String> effects, String multilineEffect, List<String> notes, JsonTextConverter<?> converter) { this.name = name; this.activity = activity; @@ -83,7 +83,7 @@ public QuteInlineAttack( public QuteInlineAttack( String name, QuteDataActivity activity, AttackRangeType rangeType, String damage, - Collection<String> damageTypes, Collection<String> traits, String note, + Collection<String> damageTypes, Collection<QuteDataRef> traits, String note, JsonTextConverter<?> converter) { this( name, activity, rangeType, null, diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteItem.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteItem.java index e599d4fe6..ad23d1965 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteItem.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteItem.java @@ -19,8 +19,8 @@ @TemplateData public class QuteItem extends Pf2eQuteBase { - /** Collection of traits (decorated links) */ - public final Collection<String> traits; + /** Collection of traits (collection of {@link QuteDataRef}) */ + public final Collection<QuteDataRef> traits; /** Aliases for this note */ public final List<String> aliases; /** @@ -66,7 +66,7 @@ public class QuteItem extends Pf2eQuteBase { public final List<QuteItemVariant> variants; public QuteItem(Pf2eSources sources, List<String> text, Tags tags, - Collection<String> traits, List<String> aliases, QuteItemActivate activate, + Collection<QuteDataRef> traits, List<String> aliases, QuteItemActivate activate, String price, String ammunition, String level, String onset, String access, String duration, String category, String group, String hands, Collection<NamedText> usage, Collection<NamedText> contract, @@ -231,8 +231,8 @@ public String toString() { public static class QuteItemWeaponData implements QuteUtil { /** Formatted string. Weapon type */ public String type; - /** Formatted string. List of traits (links) */ - public Collection<String> traits; + /** Formatted string. List of traits ({@link QuteDataRef}) */ + public Collection<QuteDataRef> traits; public Collection<NamedText> ranged; public String damage; public String group; diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteRitual.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteRitual.java index 562aff6b8..4a57d0fd1 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteRitual.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteRitual.java @@ -23,8 +23,8 @@ public class QuteRitual extends Pf2eQuteBase { public final String level; /** Type: Ritual (usually) */ public final String ritualType; - /** Collection of traits (decorated links) */ - public final Collection<String> traits; + /** Collection of traits (collection of {@link QuteDataRef}) */ + public final Collection<QuteDataRef> traits; /** Aliases for this note */ public final List<String> aliases; @@ -44,7 +44,7 @@ public class QuteRitual extends Pf2eQuteBase { public final Collection<NamedText> heightened; public QuteRitual(Pf2eSources sources, List<String> text, Tags tags, - String level, String ritualType, Collection<String> traits, List<String> aliases, + String level, String ritualType, Collection<QuteDataRef> traits, List<String> aliases, QuteRitualCasting casting, QuteRitualChecks checks, QuteSpellTarget targeting, String requirements, String duration, Collection<NamedText> heightened) { super(sources, text, tags); diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteSpell.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteSpell.java index c53d30dc1..b0c2465ba 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteSpell.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteSpell.java @@ -26,8 +26,8 @@ public class QuteSpell extends Pf2eQuteBase { public final String level; /** Type: spell, cantrip, or focus */ public final String spellType; - /** Collection of traits (decorated links) */ - public final Collection<String> traits; + /** Collection of traits (collection of {@link QuteDataRef}) */ + public final Collection<QuteDataRef> traits; /** Aliases for this note */ public final List<String> aliases; /** @@ -71,7 +71,7 @@ public class QuteSpell extends Pf2eQuteBase { public final Collection<NamedText> heightened; public QuteSpell(Pf2eSources sources, List<String> text, Tags tags, - String level, String spellType, Collection<String> traits, List<String> aliases, + String level, String spellType, Collection<QuteDataRef> traits, List<String> aliases, QuteDataDuration castDuration, List<String> components, String cost, String trigger, String requirements, QuteSpellTarget targeting, QuteSpellSave save, QuteSpellDuration duration, List<String> domains, List<String> traditions, List<String> spellLists, From bec355593a1dc7cd28a03cbf0a62e57217d58404 Mon Sep 17 00:00:00 2001 From: miscoined <miscoined@gmail.com> Date: Mon, 8 Jul 2024 12:41:34 +1000 Subject: [PATCH 13/25] =?UTF-8?q?=F0=9F=94=A5=20Remove=20getAlignmentsFrom?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace with linkifyListFrom. It's unnecessary now that we're no longer using it for creatures (which have their alignments defined directly within the trait field anyway). This also means that alignment formatting is easier to understand as it's all centralized within the linkifier now. --- .../ebullient/convert/tools/pf2e/Json2QuteDeity.java | 6 +++--- .../convert/tools/pf2e/Pf2eJsonNodeReader.java | 10 ---------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteDeity.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteDeity.java index 1c681a046..784ecb798 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteDeity.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteDeity.java @@ -40,13 +40,13 @@ protected QuteDeity buildQuteResource() { tags.add("deity", category); JsonNode alignNode = Pf2eDeity.alignment.getFrom(rootNode); - + // TODO handle "entry" field in alignment return new QuteDeity(sources, entries, tags, Field.alias.replaceTextFromList(rootNode, this), category, join(", ", Pf2eDeity.pantheon.linkifyListFrom(rootNode, Pf2eIndexType.deity, this)), - join(", ", Pf2eDeity.alignment.getAlignmentsFrom(alignNode, this)), - join(", ", Pf2eDeity.followerAlignment.getAlignmentsFrom(alignNode, this)), + join(", ", Pf2eDeity.alignment.linkifyListFrom(alignNode, Pf2eIndexType.trait, this)), + join(", ", Pf2eDeity.followerAlignment.linkifyListFrom(alignNode, Pf2eIndexType.trait, this)), Pf2eDeity.areasOfConcern.transformTextFrom(rootNode, ", ", this), commandmentToString(Pf2eDeity.edict.replaceTextFromList(rootNode, this)), commandmentToString(Pf2eDeity.anathema.replaceTextFromList(rootNode, this)), diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java index 43c8550d8..59af95c89 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java @@ -41,16 +41,6 @@ /** A utility class which extends {@link JsonNodeReader} with PF2e-specific functionality. */ public interface Pf2eJsonNodeReader extends JsonNodeReader { - /** - * Return alignments as a list of formatted strings from this field in the given node. - * Returns an empty list if we couldn't get alignments. - */ - default List<String> getAlignmentsFrom(JsonNode alignNode, JsonSource convert) { - return streamFrom(alignNode) - .map(JsonNode::asText) - .map(a -> a.length() > 2 ? a : convert.linkify(Pf2eIndexType.trait, a.toUpperCase())) - .toList(); - } /** Return a {@link QuteDataSpeed} read from this field of the {@code source} node, or null. */ default QuteDataSpeed getSpeedFrom(JsonNode source, JsonSource convert) { From 61513cc13dc8f75e8219798d93a8c54b9de7bb15 Mon Sep 17 00:00:00 2001 From: miscoined <miscoined@gmail.com> Date: Mon, 8 Jul 2024 15:51:03 +1000 Subject: [PATCH 14/25] =?UTF-8?q?=F0=9F=A7=91=F0=9F=92=BB=20Make=20replace?= =?UTF-8?q?Text=20concrete=20and=20replaceTokenText=20the=20abstract?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The implementation was the same in both trees. This makes debugging easier. --- .../dev/ebullient/convert/tools/JsonTextConverter.java | 7 ++++++- .../ebullient/convert/tools/dnd5e/JsonTextReplacement.java | 7 ++----- .../ebullient/convert/tools/pf2e/JsonTextReplacement.java | 7 ++----- .../java/dev/ebullient/convert/tools/TokenizerTest.java | 4 ++-- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/main/java/dev/ebullient/convert/tools/JsonTextConverter.java b/src/main/java/dev/ebullient/convert/tools/JsonTextConverter.java index 0978344e4..2522a3f44 100644 --- a/src/main/java/dev/ebullient/convert/tools/JsonTextConverter.java +++ b/src/main/java/dev/ebullient/convert/tools/JsonTextConverter.java @@ -591,7 +591,12 @@ default int[] outerAdmonitionIndices(List<String> inner) { return new int[] { firstLineIdx, lastLineIdx }; } - String replaceText(String s); + default String replaceText(String input) { + return replaceTokens(input, this::replaceTokenText); + } + + /** Replace specific tokens (e.g. "@"-tags) in the input string. */ + String replaceTokenText(String input, boolean nested); default String replaceText(JsonNode input) { if (input == null) { diff --git a/src/main/java/dev/ebullient/convert/tools/dnd5e/JsonTextReplacement.java b/src/main/java/dev/ebullient/convert/tools/dnd5e/JsonTextReplacement.java index 64541760b..dc8be4dbf 100644 --- a/src/main/java/dev/ebullient/convert/tools/dnd5e/JsonTextReplacement.java +++ b/src/main/java/dev/ebullient/convert/tools/dnd5e/JsonTextReplacement.java @@ -125,10 +125,6 @@ default String joinAndReplace(ArrayNode array) { return String.join(", ", list); } - default String replaceText(String input) { - return replaceTokens(input, (s, b) -> this._replaceTokenText(s, b)); - } - default String tableHeader(String x) { if (x.contains("dice")) { // don't do the usual dice formatting in a column header @@ -179,7 +175,8 @@ default String replacePromptStrings(String s) { }); } - default String _replaceTokenText(String input, boolean nested) { + @Override + default String replaceTokenText(String input, boolean nested) { String result = input; // render.js this._renderString_renderTag diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/JsonTextReplacement.java b/src/main/java/dev/ebullient/convert/tools/pf2e/JsonTextReplacement.java index f722b3db2..6331aed24 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/JsonTextReplacement.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/JsonTextReplacement.java @@ -71,11 +71,8 @@ default CompendiumConfig cfg() { return index().cfg(); } - default String replaceText(String input) { - return replaceTokens(input, (s, b) -> this._replaceTokenText(s, b)); - } - - default String _replaceTokenText(String input, boolean nested) { + @Override + default String replaceTokenText(String input, boolean nested) { if (input == null || input.isEmpty()) { return input; } diff --git a/src/test/java/dev/ebullient/convert/tools/TokenizerTest.java b/src/test/java/dev/ebullient/convert/tools/TokenizerTest.java index dbb1b3a3f..d108b2b54 100644 --- a/src/test/java/dev/ebullient/convert/tools/TokenizerTest.java +++ b/src/test/java/dev/ebullient/convert/tools/TokenizerTest.java @@ -42,8 +42,8 @@ public String linkify(IndexType type, String s) { } @Override - public String replaceText(String s) { - throw new UnsupportedOperationException("Unimplemented method 'replaceText'"); + public String replaceTokenText(String s, boolean nested) { + throw new UnsupportedOperationException("Unimplemented method 'replaceTokenText'"); } @Override From bcd0c2c8c9ddbe9b4baccfa601749ba4b70360da Mon Sep 17 00:00:00 2001 From: miscoined <miscoined@gmail.com> Date: Fri, 12 Jul 2024 18:14:54 +1000 Subject: [PATCH 15/25] =?UTF-8?q?=F0=9F=9A=B8=F0=9F=90=9B=20Add=20a=20Qute?= =?UTF-8?q?DataTraits=20and=20fix=20some=20trait/tag=20bugs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add a QuteDataTraits - dedicated class to hold traits so we can have easier bare linking - Rename collectTraitsFrom to getTraits, and pull Tag adding into QuteDataTraits - Fix creature statblock so it doesn't generate traits property when we don't have any generic traits - Fix some items being incorrectly tagged with their source (e.g. tagged as "trait/preparation-sog2" rather than "trait/preparation") - Fix some incorrectly formatted markdown links when the trait is surrounded in square brackets (e.g. for classes and magical traditions) --- .../convert/tools/pf2e/Json2QuteBase.java | 7 +- .../convert/tools/pf2e/Json2QuteDeity.java | 10 +- .../convert/tools/pf2e/Json2QuteItem.java | 2 +- .../convert/tools/pf2e/JsonSource.java | 7 +- .../tools/pf2e/JsonTextReplacement.java | 24 ++- .../tools/pf2e/Pf2eJsonNodeReader.java | 6 +- .../convert/tools/pf2e/qute/QuteDataRef.java | 2 +- .../tools/pf2e/qute/QuteDataTraits.java | 142 ++++++++++++++++++ .../tools/pf2e/qute/QuteInlineAttack.java | 15 +- .../convert/tools/pf2e/qute/QuteItem.java | 4 +- .../templates/toolsPf2e/inline-ability2md.txt | 3 +- .../templates/toolsPf2e/inline-attack2md.txt | 4 +- 12 files changed, 175 insertions(+), 51 deletions(-) create mode 100644 src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataTraits.java diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteBase.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteBase.java index f8972d50b..7fe17696f 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteBase.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteBase.java @@ -2,13 +2,12 @@ import java.util.ArrayList; import java.util.List; -import java.util.Set; import com.fasterxml.jackson.databind.JsonNode; import dev.ebullient.convert.tools.Tags; import dev.ebullient.convert.tools.pf2e.qute.Pf2eQuteBase; import dev.ebullient.convert.tools.pf2e.qute.Pf2eQuteNote; -import dev.ebullient.convert.tools.pf2e.qute.QuteDataRef; +import dev.ebullient.convert.tools.pf2e.qute.QuteDataTraits; public abstract class Json2QuteBase implements JsonSource { protected final Pf2eIndex index; @@ -16,7 +15,7 @@ public abstract class Json2QuteBase implements JsonSource { protected final JsonNode rootNode; protected final Pf2eSources sources; protected final Tags tags; - protected final Set<QuteDataRef> traits; + protected final QuteDataTraits traits; protected final List<String> entries; public Json2QuteBase(Pf2eIndex index, Pf2eIndexType type, JsonNode rootNode) { @@ -29,7 +28,7 @@ public Json2QuteBase(Pf2eIndex index, Pf2eIndexType type, JsonNode rootNode, Pf2 this.rootNode = rootNode; this.sources = sources; this.tags = new Tags(sources); - this.traits = collectTraitsFrom(rootNode, tags); + this.traits = getTraits(rootNode).addToTags(tags); this.entries = new ArrayList<>(SourceField.entries.transformListFrom(rootNode, this, "##")); } diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteDeity.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteDeity.java index 784ecb798..4ec4d3e73 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteDeity.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteDeity.java @@ -6,7 +6,6 @@ import static dev.ebullient.convert.StringUtil.toOrdinal; import static dev.ebullient.convert.StringUtil.toTitleCase; -import java.util.Collection; import java.util.List; import java.util.Map; import java.util.TreeMap; @@ -19,7 +18,6 @@ import dev.ebullient.convert.qute.NamedText; import dev.ebullient.convert.tools.pf2e.Pf2eJsonNodeReader.Pf2eAttack; import dev.ebullient.convert.tools.pf2e.qute.QuteDataActivity.Activity; -import dev.ebullient.convert.tools.pf2e.qute.QuteDataRef; import dev.ebullient.convert.tools.pf2e.qute.QuteDeity; import dev.ebullient.convert.tools.pf2e.qute.QuteInlineAttack; import dev.ebullient.convert.tools.pf2e.qute.QuteInlineAttack.AttackRangeType; @@ -164,10 +162,6 @@ private NamedText buildAvatarAbility(JsonNode abilityNode) { } private QuteInlineAttack buildAvatarAttack(JsonNode actionNode, AttackRangeType rangeType) { - Collection<QuteDataRef> traits = collectTraitsFrom(actionNode, tags); - Pf2eDeity.preciousMetal.getListOfStrings(actionNode, tui()).stream().map(QuteDataRef::new).forEach(traits::add); - Pf2eDeity.traitNote.getTextFrom(actionNode).map(QuteDataRef::new).ifPresent(traits::add); - return new QuteInlineAttack( Pf2eAttack.name.getTextOrDefault(actionNode, "attack"), Pf2eActivity.toQuteActivity(this, Activity.single, null), @@ -177,7 +171,9 @@ private QuteInlineAttack buildAvatarAttack(JsonNode actionNode, AttackRangeType .map(field -> field.getTextOrEmpty(actionNode)) .filter(StringUtil::isPresent) .toList(), - traits, + getTraits(actionNode).addToTags(tags) + .addTraits(Pf2eDeity.preciousMetal.getListOfStrings(actionNode, tui())) + .addTrait(Pf2eDeity.traitNote.getTextOrEmpty(actionNode)), Pf2eDeity.note.replaceTextFrom(actionNode, this), this); } diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteItem.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteItem.java index 6f328016e..6db0ab0d1 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteItem.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteItem.java @@ -318,7 +318,7 @@ public static QuteItemWeaponData buildWeaponData(JsonNode source, JsonSource convert, Tags tags) { QuteItemWeaponData weaponData = new QuteItemWeaponData(); - weaponData.traits = convert.collectTraitsFrom(source, tags); + weaponData.traits = convert.getTraits(source).addToTags(tags); weaponData.type = SourceField.type.getTextOrEmpty(source); weaponData.damage = getDamageString(source, convert); diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java b/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java index 0229c2b4d..00aeb0c9f 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java @@ -3,7 +3,6 @@ import static dev.ebullient.convert.StringUtil.join; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.stream.Collectors; import com.fasterxml.jackson.databind.JsonNode; @@ -14,11 +13,9 @@ import dev.ebullient.convert.io.Tui; import dev.ebullient.convert.qute.QuteUtil; import dev.ebullient.convert.tools.JsonNodeReader.FieldValue; -import dev.ebullient.convert.tools.Tags; import dev.ebullient.convert.tools.pf2e.Json2QuteItem.Pf2eItem; import dev.ebullient.convert.tools.pf2e.qute.Pf2eQuteBase; import dev.ebullient.convert.tools.pf2e.qute.QuteDataActivity; -import dev.ebullient.convert.tools.pf2e.qute.QuteDataRef; public interface JsonSource extends JsonTextReplacement { @@ -585,9 +582,7 @@ default List<String> embedGenericData(String tag, JsonNode data) { text.add("title: " + title); // Add traits - Tags tags = new Tags(); - Collection<QuteDataRef> traits = collectTraitsFrom(data, tags); - text.add(join(" ", traits) + " "); + text.add(join(" ", getTraits(data)) + " "); maybeAddBlankLine(text); // Add rendered sections diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/JsonTextReplacement.java b/src/main/java/dev/ebullient/convert/tools/pf2e/JsonTextReplacement.java index 6331aed24..bd67d3149 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/JsonTextReplacement.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/JsonTextReplacement.java @@ -7,11 +7,9 @@ import java.util.ArrayList; import java.util.List; -import java.util.Set; -import java.util.TreeSet; import java.util.regex.MatchResult; import java.util.regex.Pattern; -import java.util.stream.Collectors; +import java.util.stream.Collector; import com.fasterxml.jackson.databind.JsonNode; import dev.ebullient.convert.config.CompendiumConfig; @@ -20,9 +18,9 @@ import dev.ebullient.convert.tools.JsonNodeReader; import dev.ebullient.convert.tools.JsonNodeReader.FieldValue; import dev.ebullient.convert.tools.JsonTextConverter; -import dev.ebullient.convert.tools.Tags; import dev.ebullient.convert.tools.pf2e.qute.QuteDataActivity.Activity; import dev.ebullient.convert.tools.pf2e.qute.QuteDataRef; +import dev.ebullient.convert.tools.pf2e.qute.QuteDataTraits; public interface JsonTextReplacement extends JsonTextConverter<Pf2eIndexType> { enum Field implements Pf2eJsonNodeReader { @@ -209,17 +207,15 @@ default String replaceActionAs(MatchResult match) { /** * Collect and linkify traits from the specified node. * - * @param tags The tags to populate while collecting traits. If null, then don't populate any tags. - * - * @return a set of {@link QuteDataRef}s to trait notes, or an empty set (never null) + * @return a {@link QuteDataTraits} which may be empty (never null) */ - default Set<QuteDataRef> collectTraitsFrom(JsonNode sourceNode, Tags tags) { + default QuteDataTraits getTraits(JsonNode sourceNode) { return Field.traits.getListOfStrings(sourceNode, tui()).stream() - .peek(tags == null ? (t -> {}) : t -> tags.add("trait", t)) - .sorted() - .map(s -> linkify(Pf2eIndexType.trait, s)) - .map(QuteDataRef::fromMarkdownLink) - .collect(Collectors.toCollection(TreeSet::new)); + .map(s -> QuteDataRef.fromMarkdownLink(linkify(Pf2eIndexType.trait, s))) + .collect(Collector.of(QuteDataTraits::new, QuteDataTraits::add, (a, b) -> { + a.addAll(b); + return b; + })); } default String linkifyRuneItem(MatchResult match) { @@ -363,6 +359,8 @@ default String linkifyTrait(String match) { default String linkifyTrait(JsonNode traitNode, String linkText) { if (traitNode != null) { String source = SourceField.source.getTextOrEmpty(traitNode); + // Some traits are surrounded in square brackets. Strip this out to avoid messing up link rendering. + linkText = linkText.replaceFirst("^\\[(.*)]$", "$1"); return "[%s](%s/%s%s.md \"%s\")".formatted( linkText, diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java index 59af95c89..8fc1e3a7d 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonNodeReader.java @@ -7,11 +7,11 @@ import static java.util.Objects.requireNonNullElse; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collector; @@ -95,7 +95,7 @@ default List<QuteInlineAttack> getAttacksFrom(JsonNode source, JsonSource conver * traits from these activation components to {@code traits}. Return an empty list if we couldn't get activation * components. */ - default List<String> getActivationComponentsFrom(JsonNode source, Set<QuteDataRef> traits, JsonSource convert) { + default List<String> getActivationComponentsFrom(JsonNode source, Collection<QuteDataRef> traits, JsonSource convert) { List<String> rawComponents = getListOfStrings(source, convert.tui()).stream() .map(s -> s.replaceFirst("^\\((%s)\\)$", "\1")) // remove parens .toList(); @@ -667,7 +667,7 @@ public static QuteInlineAttack getAttack(JsonNode node, JsonSource convert) { attack.intOrNull(node), formattedDamage, types.replaceTextFromList(node, convert), - convert.collectTraitsFrom(node, null), + convert.getTraits(node), hasMultilineEffect ? List.of() : attackEffects, hasMultilineEffect ? String.join("\n", attackEffects) : null, noMAP.booleanOrDefault(node, false) ? List.of() : List.of("no multiple attack penalty"), diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataRef.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataRef.java index d7cd43c83..d689a82b7 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataRef.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataRef.java @@ -16,7 +16,7 @@ */ public record QuteDataRef(String displayText, String notePath, String title) implements Comparable<QuteDataRef> { - private static final Pattern MARKDOWN_LINK_PAT = Pattern.compile("^\\[(?<display>[^]]+)]\\((?<path>.*?)(?: \"(?<title>.*)\")?\\)$"); + private static final Pattern MARKDOWN_LINK_PAT = Pattern.compile("^\\[(?<display>.+)]\\((?<path>.*?)(?: \"(?<title>.*)\")?\\)$"); public QuteDataRef(String displayText) { this(displayText, null, null); diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataTraits.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataTraits.java new file mode 100644 index 000000000..e207e20c2 --- /dev/null +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataTraits.java @@ -0,0 +1,142 @@ +package dev.ebullient.convert.tools.pf2e.qute; + +import static dev.ebullient.convert.StringUtil.isPresent; +import static dev.ebullient.convert.StringUtil.join; +import static dev.ebullient.convert.StringUtil.joiningNonEmpty; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Optional; +import java.util.Set; +import java.util.TreeSet; +import java.util.stream.Collectors; + +import dev.ebullient.convert.tools.Tags; + +/** A collection of traits stored as {@link QuteDataRef}s to the trait note. */ +public class QuteDataTraits implements Collection<QuteDataRef> { + private final Set<QuteDataRef> refs = new TreeSet<>(); + + public QuteDataTraits() {} + + /** The first trait which has this category, as a {@link QuteDataRef}. Case-sensitive. */ + public QuteDataRef getFirst(String category) { + return refs.stream().filter(ref -> ref.title() != null && ref.title().contains(category)).findFirst().orElse(null); + } + + /** Return these traits as a comma-delimited string without any extra formatting (eg no title attributes). */ + public String formattedWithoutTitles() { + return refs.stream().map(QuteDataRef::withoutTitle).collect(joiningNonEmpty(", ")); + } + + /** Return traits without any size, alignment, or rarity traits. */ + public QuteDataTraits getGenericTraits() { + return refs.stream() + .filter(ref -> !isPresent(ref.title()) || + !(ref.title().contains("Alignment") || ref.title().contains("Size") || ref.title().contains("Rarity"))) + .collect(Collectors.toCollection(QuteDataTraits::new)); + } + + public QuteDataTraits addToTags(Tags tags) { + for (QuteDataRef ref : this) { + tags.add("trait", ref.displayText()); + } + return this; + } + + public QuteDataTraits addTrait(String trait) { + if (isPresent(trait)) { + refs.add(new QuteDataRef(trait)); + } + return this; + } + + public QuteDataTraits addTraits(Collection<String> c) { + c.forEach(this::addTrait); + return this; + } + + @Override + public String toString() { + return join(", ", refs); + } + + @Override + public int size() { + return refs.size(); + } + + @Override + public boolean isEmpty() { + return refs.isEmpty(); + } + + @Override + public boolean contains(Object o) { + if (o instanceof QuteDataRef) { + return refs.contains(o); + } else if (o instanceof String) { + return refs.stream().anyMatch(ref -> ref.displayText().equals(o)); + } + return false; + } + + @Override + public boolean remove(Object o) { + if (o instanceof QuteDataRef) { + return refs.remove(o); + } else if (o instanceof String) { + Optional<QuteDataRef> ref = refs.stream().filter(r -> r.displayText().equals(o)).findAny(); + if (ref.isEmpty()) { + return false; + } + return refs.remove(ref); + } + return false; + } + + @Override + public boolean add(QuteDataRef quteDataRef) { + return refs.add(quteDataRef); + } + + @Override + public Iterator<QuteDataRef> iterator() { + return refs.iterator(); + } + + @Override + public Object[] toArray() { + return refs.toArray(); + } + + @Override + public <T> T[] toArray(T[] a) { + return refs.toArray(a); + } + + @Override + public boolean containsAll(Collection<?> c) { + return c.stream().allMatch(this::contains); + } + + @Override + public boolean addAll(Collection<? extends QuteDataRef> c) { + return c.stream().allMatch(this::add); + } + + @Override + public boolean removeAll(Collection<?> c) { + return c.stream().allMatch(this::remove); + } + + @Override + public boolean retainAll(Collection<?> c) { + return refs.removeIf(ref -> !c.contains(ref) && !c.contains(ref.displayText())); + } + + @Override + public void clear() { + refs.clear(); + } +} diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteInlineAttack.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteInlineAttack.java index 69a92705b..be6796816 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteInlineAttack.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteInlineAttack.java @@ -1,7 +1,5 @@ package dev.ebullient.convert.tools.pf2e.qute; -import static dev.ebullient.convert.StringUtil.join; -import static dev.ebullient.convert.StringUtil.parenthesize; import static dev.ebullient.convert.StringUtil.toTitleCase; import java.util.Collection; @@ -46,8 +44,8 @@ public final class QuteInlineAttack implements QuteDataGenericStat, QuteUtil.Ren */ public final Collection<String> damageTypes; - /** Any traits associated with the attack (collection of {@link QuteDataRef}) */ - public final Collection<QuteDataRef> traits; + /** Traits associated with the attack as a {@link QuteDataTraits} */ + public final QuteDataTraits traits; /** * Any additional effects associated with the attack e.g. grab (list of strings). Effects listed here @@ -66,7 +64,7 @@ public final class QuteInlineAttack implements QuteDataGenericStat, QuteUtil.Ren public QuteInlineAttack( String name, QuteDataActivity activity, AttackRangeType rangeType, Integer attackBonus, String damage, - Collection<String> damageTypes, Collection<QuteDataRef> traits, List<String> effects, String multilineEffect, + Collection<String> damageTypes, QuteDataTraits traits, List<String> effects, String multilineEffect, List<String> notes, JsonTextConverter<?> converter) { this.name = name; this.activity = activity; @@ -83,7 +81,7 @@ public QuteInlineAttack( public QuteInlineAttack( String name, QuteDataActivity activity, AttackRangeType rangeType, String damage, - Collection<String> damageTypes, Collection<QuteDataRef> traits, String note, + Collection<String> damageTypes, QuteDataTraits traits, String note, JsonTextConverter<?> converter) { this( name, activity, rangeType, null, @@ -116,11 +114,6 @@ public String toString() { return render(); } - /** Return traits formatted as a single string, e.g. {@code (agile, trip, finesse)} */ - public String formattedTraits() { - return parenthesize(join(", ", traits)); - } - public enum AttackRangeType { RANGED, MELEE; diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteItem.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteItem.java index ad23d1965..ea1f1e43a 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteItem.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteItem.java @@ -231,8 +231,8 @@ public String toString() { public static class QuteItemWeaponData implements QuteUtil { /** Formatted string. Weapon type */ public String type; - /** Formatted string. List of traits ({@link QuteDataRef}) */ - public Collection<QuteDataRef> traits; + /** Traits as a {@link QuteDataTraits} */ + public QuteDataTraits traits; public Collection<NamedText> ranged; public String damage; public String group; diff --git a/src/main/resources/templates/toolsPf2e/inline-ability2md.txt b/src/main/resources/templates/toolsPf2e/inline-ability2md.txt index 1394f6edf..15d46b3db 100644 --- a/src/main/resources/templates/toolsPf2e/inline-ability2md.txt +++ b/src/main/resources/templates/toolsPf2e/inline-ability2md.txt @@ -1,6 +1,7 @@ +{#let componentsTraits = (resource.components.join(", ") + (resource.components && resource.traits ? " " : "") + (resource.traits ? (str:format("(%s)", resource.traits.formattedWithoutTitles)) : ""))} ```ad-embed-ability {#if resource.hasDetails } -title: **{#if resource.reference}{resource.reference}{#else}{resource.name}{/if}** {resource.activity}{resource.components.join(", ").prefixSpace}{#if resource.traits} ({resource.bareTraitList}){/if} +title: **{#if resource.reference}{resource.reference}{#else}{resource.name}{/if}** {resource.activity}{componentsTraits.prefixSpace} {#if resource.note} > [!pf2-note] > {resource.note} diff --git a/src/main/resources/templates/toolsPf2e/inline-attack2md.txt b/src/main/resources/templates/toolsPf2e/inline-attack2md.txt index 1c5ad5b56..a5d9b4a77 100644 --- a/src/main/resources/templates/toolsPf2e/inline-attack2md.txt +++ b/src/main/resources/templates/toolsPf2e/inline-attack2md.txt @@ -1,7 +1,7 @@ {#let r=resource} {#if r.multilineEffect} ```ad-inline-attack -title: {r.rangeType} {r.activity} {r.name.capitalized}{r.bonus.prefixSpace}{r.formattedTraits.prefixSpace} +title: {r.rangeType} {r.activity} {r.name.capitalized}{r.bonus.prefixSpace}{#if r.traits} ({r.traits}){/if} {#if r.damage} **Damage** {r.damage} {/if}{#if r.multilineEffect} @@ -9,5 +9,5 @@ title: {r.rangeType} {r.activity} {r.name.capitalized}{r.bonus.prefixSpace}{r.fo {/if} ``` {#else} -- **{r.rangeType}** {r.activity} {r.name}{r.bonus.prefixSpace}{r.formattedTraits.prefixSpace}{#if r.damage}, **Damage** {r.damage}{/if} +- **{r.rangeType}** {r.activity} {r.name}{r.bonus.prefixSpace}{#if r.traits} ({r.traits}){/if}{#if r.damage}, **Damage** {r.damage}{/if} {/if} From 1d270f0f4fd75c84ebca10c93ee66d5ee08299b2 Mon Sep 17 00:00:00 2001 From: miscoined <miscoined@gmail.com> Date: Tue, 11 Feb 2025 17:28:05 +1100 Subject: [PATCH 16/25] =?UTF-8?q?=F0=9F=94=A8=20Don't=20fail=20tests=20if?= =?UTF-8?q?=20git=20properties=20can't=20be=20found?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/config/config.5e.json | 92 +++--- examples/config/config.pf2e.json | 62 ++-- examples/config/config.schema.json | 290 +++++++++--------- .../ebullient/convert/VersionProvider.java | 11 +- 4 files changed, 228 insertions(+), 227 deletions(-) diff --git a/examples/config/config.5e.json b/examples/config/config.5e.json index ed6ad7f0b..162034c7c 100644 --- a/examples/config/config.5e.json +++ b/examples/config/config.5e.json @@ -1,47 +1,47 @@ -{ - "sources" : { - "toolsRoot" : "local/5etools/data", - "reference" : [ - "DMG" - ], - "adventure" : [ - "LMoP" - ], - "book" : [ - "PHB" - ], - "homebrew" : [ - "homebrew/collection/Kobold Press; Deep Magic 14 Elemental Magic.json" - ] - }, - "paths" : { - "compendium" : "/compendium/", - "rules" : "/compendium/rules/" - }, - "include" : [ - "race|changeling|mpmm" - ], - "includeGroup" : [ - "familiars" - ], - "exclude" : [ - "monster|expert|dc", - "monster|expert|sdw", - "monster|expert|slw" - ], - "excludePattern" : [ - "race\\|.*\\|dmg" - ], - "reprintBehavior" : "newest", - "template" : { - "background" : "examples/templates/tools5e/images-background2md.txt" - }, - "useDiceRoller" : true, - "yamlStatblocks" : true, - "tagPrefix" : "ttrpg-cli", - "images" : { - "internalRoot" : "local/path/for/remote/images", - "copyInternal" : true, - "copyExternal" : true - } +{ + "sources" : { + "toolsRoot" : "local/5etools/data", + "reference" : [ + "DMG" + ], + "adventure" : [ + "LMoP" + ], + "book" : [ + "PHB" + ], + "homebrew" : [ + "homebrew/collection/Kobold Press; Deep Magic 14 Elemental Magic.json" + ] + }, + "paths" : { + "compendium" : "/compendium/", + "rules" : "/compendium/rules/" + }, + "include" : [ + "race|changeling|mpmm" + ], + "includeGroup" : [ + "familiars" + ], + "exclude" : [ + "monster|expert|dc", + "monster|expert|sdw", + "monster|expert|slw" + ], + "excludePattern" : [ + "race\\|.*\\|dmg" + ], + "reprintBehavior" : "newest", + "template" : { + "background" : "examples/templates/tools5e/images-background2md.txt" + }, + "useDiceRoller" : true, + "yamlStatblocks" : true, + "tagPrefix" : "ttrpg-cli", + "images" : { + "internalRoot" : "local/path/for/remote/images", + "copyInternal" : true, + "copyExternal" : true + } } \ No newline at end of file diff --git a/examples/config/config.pf2e.json b/examples/config/config.pf2e.json index f6a82e75e..cdeccf927 100644 --- a/examples/config/config.pf2e.json +++ b/examples/config/config.pf2e.json @@ -1,32 +1,32 @@ -{ - "sources" : { - "reference" : [ - "CRB", - "GMG" - ], - "book" : [ - "crb", - "gmg" - ] - }, - "paths" : { - "compendium" : "compendium/", - "rules" : "compendium/rules/" - }, - "include" : [ - "ability|buck|b1" - ], - "exclude" : [ - "background|insurgent|apg" - ], - "excludePattern" : [ - "background\\|.*\\|lowg" - ], - "reprintBehavior" : "newest", - "template" : { - "ability" : "../path/to/ability2md.txt" - }, - "useDiceRoller" : true, - "tagPrefix" : "ttrpg-cli", - "images" : { } +{ + "sources" : { + "reference" : [ + "CRB", + "GMG" + ], + "book" : [ + "crb", + "gmg" + ] + }, + "paths" : { + "compendium" : "compendium/", + "rules" : "compendium/rules/" + }, + "include" : [ + "ability|buck|b1" + ], + "exclude" : [ + "background|insurgent|apg" + ], + "excludePattern" : [ + "background\\|.*\\|lowg" + ], + "reprintBehavior" : "newest", + "template" : { + "ability" : "../path/to/ability2md.txt" + }, + "useDiceRoller" : true, + "tagPrefix" : "ttrpg-cli", + "images" : { } } \ No newline at end of file diff --git a/examples/config/config.schema.json b/examples/config/config.schema.json index 4b2daa621..6e11c401c 100644 --- a/examples/config/config.schema.json +++ b/examples/config/config.schema.json @@ -1,146 +1,146 @@ -{ - "$schema" : "https://json-schema.org/draft/2020-12/schema", - "$defs" : { - "Map(String,String)" : { - "type" : "object" - } - }, - "type" : "object", - "properties" : { - "exclude" : { - "type" : "array", - "items" : { - "type" : "string" - } - }, - "excludePattern" : { - "type" : "array", - "items" : { - "type" : "string" - } - }, - "from" : { - "type" : "array", - "items" : { - "type" : "string" - } - }, - "fullSource" : { - "type" : "object", - "properties" : { - "adventure" : { - "type" : "array", - "items" : { - "type" : "string" - } - }, - "book" : { - "type" : "array", - "items" : { - "type" : "string" - } - }, - "homebrew" : { - "type" : "array", - "items" : { - "type" : "string" - } - } - } - }, - "images" : { - "type" : "object", - "properties" : { - "copyExternal" : { - "type" : "boolean" - }, - "copyInternal" : { - "type" : "boolean" - }, - "fallbackPaths" : { - "$ref" : "#/$defs/Map(String,String)" - }, - "internalRoot" : { - "type" : "string" - } - } - }, - "include" : { - "type" : "array", - "items" : { - "type" : "string" - } - }, - "includeGroup" : { - "type" : "array", - "items" : { - "type" : "string" - } - }, - "includePattern" : { - "type" : "array", - "items" : { - "type" : "string" - } - }, - "paths" : { - "type" : "object", - "properties" : { - "compendium" : { - "type" : "string" - }, - "rules" : { - "type" : "string" - } - } - }, - "reprintBehavior" : { - "type" : "string", - "enum" : [ "newest", "edition", "all" ] - }, - "sources" : { - "type" : "object", - "properties" : { - "adventure" : { - "type" : "array", - "items" : { - "type" : "string" - } - }, - "book" : { - "type" : "array", - "items" : { - "type" : "string" - } - }, - "homebrew" : { - "type" : "array", - "items" : { - "type" : "string" - } - }, - "reference" : { - "type" : "array", - "items" : { - "type" : "string" - } - }, - "toolsRoot" : { - "type" : "string" - } - } - }, - "tagPrefix" : { - "type" : "string" - }, - "template" : { - "$ref" : "#/$defs/Map(String,String)" - }, - "useDiceRoller" : { - "type" : "boolean" - }, - "yamlStatblocks" : { - "type" : "boolean" - } - } +{ + "$schema" : "https://json-schema.org/draft/2020-12/schema", + "$defs" : { + "Map(String,String)" : { + "type" : "object" + } + }, + "type" : "object", + "properties" : { + "exclude" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, + "excludePattern" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, + "from" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, + "fullSource" : { + "type" : "object", + "properties" : { + "adventure" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, + "book" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, + "homebrew" : { + "type" : "array", + "items" : { + "type" : "string" + } + } + } + }, + "images" : { + "type" : "object", + "properties" : { + "copyExternal" : { + "type" : "boolean" + }, + "copyInternal" : { + "type" : "boolean" + }, + "fallbackPaths" : { + "$ref" : "#/$defs/Map(String,String)" + }, + "internalRoot" : { + "type" : "string" + } + } + }, + "include" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, + "includeGroup" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, + "includePattern" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, + "paths" : { + "type" : "object", + "properties" : { + "compendium" : { + "type" : "string" + }, + "rules" : { + "type" : "string" + } + } + }, + "reprintBehavior" : { + "type" : "string", + "enum" : [ "newest", "edition", "all" ] + }, + "sources" : { + "type" : "object", + "properties" : { + "adventure" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, + "book" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, + "homebrew" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, + "reference" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, + "toolsRoot" : { + "type" : "string" + } + } + }, + "tagPrefix" : { + "type" : "string" + }, + "template" : { + "$ref" : "#/$defs/Map(String,String)" + }, + "useDiceRoller" : { + "type" : "boolean" + }, + "yamlStatblocks" : { + "type" : "boolean" + } + } } \ No newline at end of file diff --git a/src/main/java/dev/ebullient/convert/VersionProvider.java b/src/main/java/dev/ebullient/convert/VersionProvider.java index b556649c6..4761a38a5 100644 --- a/src/main/java/dev/ebullient/convert/VersionProvider.java +++ b/src/main/java/dev/ebullient/convert/VersionProvider.java @@ -13,12 +13,13 @@ public String[] getVersion() { Properties properties = new Properties(); try { properties.load(TtrpgConfig.class.getResourceAsStream("/git.properties")); - return new String[] { - "${COMMAND-FULL-NAME} version " + properties.getProperty("git.build.version"), - "Git commit: " + properties.get("git.commit.id.abbrev") - }; - } catch (IOException e) { + } catch (IOException | NullPointerException e) { return new String[] { "${COMMAND-FULL-NAME} version unknown " }; } + + return new String[] { + "${COMMAND-FULL-NAME} version " + properties.getProperty("git.build.version"), + "Git commit: " + properties.get("git.commit.id.abbrev") + }; } } From 6bd89afd56a13c1c0b96d70848a0dc8d9eeae874 Mon Sep 17 00:00:00 2001 From: miscoined <miscoined@gmail.com> Date: Fri, 12 Jul 2024 23:00:38 +1000 Subject: [PATCH 17/25] =?UTF-8?q?=F0=9F=9A=B8=F0=9F=92=A5=20Improve=20Qute?= =?UTF-8?q?ItemArmorData?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 💥 Rename some properties to better reflect their usage - 🚸 Expose integers rather than formatted strings to the template - Add some StringUtil helpers for printing modifiers - Make the default output match the printed book text better --- .../dev/ebullient/convert/StringUtil.java | 12 +++- .../convert/tools/JsonNodeReader.java | 12 ---- .../convert/tools/pf2e/Json2QuteItem.java | 35 +++++------- .../convert/tools/pf2e/qute/QuteItem.java | 57 ++++++++++--------- .../resources/templates/toolsPf2e/item2md.txt | 2 +- 5 files changed, 53 insertions(+), 65 deletions(-) diff --git a/src/main/java/dev/ebullient/convert/StringUtil.java b/src/main/java/dev/ebullient/convert/StringUtil.java index 1f1d380c8..165d5a46f 100644 --- a/src/main/java/dev/ebullient/convert/StringUtil.java +++ b/src/main/java/dev/ebullient/convert/StringUtil.java @@ -25,6 +25,14 @@ */ public class StringUtil { + /** Return the number with prefixed with the appropriate sign (+ or -), or an empty string if null. */ + public static String formatAsModifier(Integer n) { + if (n == null) { + return ""; + } + return (n < 0 ? "-" : "+") + Math.abs(n); + } + /** * Return {@code formatString} formatted with {@code o} as the first parameter. * If {@code o} is null, then return an empty string. @@ -33,8 +41,8 @@ public static String formatIfPresent(String formatString, Object val) { return val == null || val.toString().isBlank() ? "" : formatString.formatted(val); } - public static String valueOrDefault(String value, String fallback) { - return value == null || value.isEmpty() ? fallback : value; + public static String valueOrDefault(Object value, String fallback) { + return value == null || value.toString().isEmpty() ? fallback : value.toString(); } public static String valueOrDefault(String[] parts, int index, String fallback) { diff --git a/src/main/java/dev/ebullient/convert/tools/JsonNodeReader.java b/src/main/java/dev/ebullient/convert/tools/JsonNodeReader.java index 79a298a73..e40748cca 100644 --- a/src/main/java/dev/ebullient/convert/tools/JsonNodeReader.java +++ b/src/main/java/dev/ebullient/convert/tools/JsonNodeReader.java @@ -48,18 +48,6 @@ default void appendUnlessEmptyFrom(JsonNode x, List<String> text, JsonTextConver } } - default String bonusOrNull(JsonNode x) { - JsonNode value = getFrom(x); - if (value == null) { - return null; - } - if (!value.isNumber()) { - throw new IllegalArgumentException("bonusOrNull can only work with numbers: " + value); - } - int n = value.asInt(); - return (n >= 0 ? "+" : "") + n; - } - /** * Return the boolean value of the field in the node: * - if the field is a boolean, return the value diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteItem.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteItem.java index 6db0ab0d1..90d6bb363 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteItem.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteItem.java @@ -52,7 +52,7 @@ protected Pf2eQuteBase buildQuteResource() { keysToList(List.of(Pf2eItem.usage, Pf2eItem.bulk)), getContract(), getShieldData(), - getArmorData(), + Pf2eItem.armorData.getArmorFrom(rootNode), getWeaponData(), getVariants(), Pf2eItem.craftReq.transformTextFrom(rootNode, "; ", this)); @@ -107,27 +107,6 @@ private QuteItemShieldData getShieldData() { penalty(Pf2eItem.speedPen.getTextOrEmpty(shieldNode), " ft.")); } - private QuteItemArmorData getArmorData() { - JsonNode armorDataNode = Pf2eItem.armorData.getFrom(rootNode); - if (armorDataNode == null) { - return null; - } - - QuteItemArmorData armorData = new QuteItemArmorData(); - Pf2eItem.ac.intFrom(armorDataNode).ifPresent(ac -> armorData.ac = new QuteDataArmorClass(ac)); - armorData.dexCap = Pf2eItem.dexCap.bonusOrNull(armorDataNode); - - armorData.strength = Pf2eItem.str.getTextOrDefault(armorDataNode, "—"); - - String checkPen = Pf2eItem.checkPen.getTextOrDefault(armorDataNode, null); - armorData.checkPenalty = penalty(checkPen, ""); - - String speedPen = Pf2eItem.speedPen.getTextOrDefault(armorDataNode, null); - armorData.speedPenalty = penalty(speedPen, " ft."); - - return armorData; - } - private List<QuteItemWeaponData> getWeaponData() { JsonNode weaponDataNode = Pf2eItem.weaponData.getFrom(rootNode); if (weaponDataNode == null) { @@ -294,6 +273,18 @@ enum Pf2eItem implements Pf2eJsonNodeReader { String properName() { return toTitleCase(this.nodeName()); } + + private QuteItemArmorData getArmorFrom(JsonNode source) { + return getObjectFrom(source) + .map(node -> new QuteItemArmorData( + ac.intFrom(node).map(QuteDataArmorClass::new).orElseThrow(), + dexCap.intOrNull(node), + str.intOrNull(node), + checkPen.intFrom(node).map(n -> -Math.abs(n)).orElse(0), + speedPen.intFrom(node).map(n -> -Math.abs(n)).orElse(0) + )) + .orElse(null); + } } enum Pf2eItemVariant implements Pf2eJsonNodeReader { diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteItem.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteItem.java index ea1f1e43a..5fb9bf53d 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteItem.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteItem.java @@ -1,5 +1,9 @@ package dev.ebullient.convert.tools.pf2e.qute; +import static dev.ebullient.convert.StringUtil.formatAsModifier; +import static dev.ebullient.convert.StringUtil.join; +import static dev.ebullient.convert.StringUtil.valueOrDefault; + import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -167,41 +171,38 @@ public String toString() { } /** - * Pf2eTools item armor attributes + * Armor statistics + * <blockquote> + * <b>AC Bonus</b> +2; <b>Dex Cap</b> +0; <b>Check Penalty</b> -3; <b>Speed Penalty</b> -10 ft; <b>Strength</b> 14 + * </blockquote> * * This data object provides a default mechanism for creating * a marked up string based on the attributes that are present. * To use it, reference it directly: `{resource.armor}`. + * + * @param acBonus AC bonus granted by the armor as a {@link QuteDataArmorClass}. Never null. + * @param dexCap The dex modifier cap that applies while wearing this armor, or null. + * @param strengthReq The strength requirement to reduce some penalties while wearing the armor, or null. + * @param checkPenalty The penalty to Strength-and-Dex-based skill checks that apply if the strength requirement is not met. + * Integer, always negative or 0. + * @param speedPenalty The penalty to speed that applies when wearing this armor. Integer, always negative or 0. */ @TemplateData - public static class QuteItemArmorData implements QuteUtil { - /** {@link dev.ebullient.convert.tools.pf2e.qute.QuteDataArmorClass Item armor class details} */ - public QuteDataArmorClass ac; - /** Formatted string. Dex cap */ - public String dexCap; - /** Formatted string. Armor strength */ - public String strength; - /** Formatted string. Check penalty */ - public String checkPenalty; - /** Formatted string. Speed penalty */ - public String speedPenalty; - + public record QuteItemArmorData( + QuteDataArmorClass acBonus, + Integer dexCap, + Integer strengthReq, + int checkPenalty, + int speedPenalty + ) implements QuteUtil { + @Override public String toString() { - List<String> parts = new ArrayList<>(); - parts.add("**AC Bonus** " + ac.bonus()); - if (isPresent(dexCap)) { - parts.add("**Dex Cap** " + dexCap); - } - if (isPresent(strength)) { - parts.add("**Strength** " + strength); - } - if (isPresent(checkPenalty)) { - parts.add("**Check Penalty** " + checkPenalty); - } - if (isPresent(speedPenalty)) { - parts.add("**Speed Penalty** " + speedPenalty); - } - return "- " + String.join("; ", parts); + return join("; ", + "**AC Bonus** " + acBonus.bonus(), + "**Dex Cap** " + valueOrDefault(formatAsModifier(dexCap), "—"), + "**Check Penalty** " + (checkPenalty != 0 ? formatAsModifier(checkPenalty) : "—"), + "**Speed Penalty** " + (speedPenalty != 0 ? (formatAsModifier(speedPenalty) + " ft.") : "—"), + "**Strength** " + valueOrDefault(strengthReq, "—")); } } diff --git a/src/main/resources/templates/toolsPf2e/item2md.txt b/src/main/resources/templates/toolsPf2e/item2md.txt index 48b04cbd7..d6dc04531 100644 --- a/src/main/resources/templates/toolsPf2e/item2md.txt +++ b/src/main/resources/templates/toolsPf2e/item2md.txt @@ -34,7 +34,7 @@ aliases: ["{resource.name}"{#each resource.aliases}, "{it}"{/each}] {/if}{#if resource.shield } {resource.shield} {/if}{#if resource.armor } -{resource.armor} +- {resource.armor} {/if}{#if resource.weapons } {#each resource.weapons}{it} {/each}{/if}{#if resource.hands } From b68f78431398b47b4cb0c8a3d13bd901e7a12190 Mon Sep 17 00:00:00 2001 From: miscoined <miscoined@gmail.com> Date: Sun, 7 Jul 2024 18:40:12 +1000 Subject: [PATCH 18/25] =?UTF-8?q?=F0=9F=A7=AA=20Add=20a=20test=20for=20pf2?= =?UTF-8?q?e=20yaml=20statblock=20templates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/dev/ebullient/convert/TestUtils.java | 42 +++++++++++++++++++ .../convert/tools/dnd5e/CommonDataTests.java | 37 +--------------- .../convert/tools/pf2e/CommonDataTests.java | 20 +++++---- .../pf2e/Pf2eJsonDataYamlStatblockTest.java | 26 ++++++++++++ src/test/resources/pf2e-yaml.json | 5 +++ 5 files changed, 85 insertions(+), 45 deletions(-) create mode 100644 src/test/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonDataYamlStatblockTest.java create mode 100644 src/test/resources/pf2e-yaml.json diff --git a/src/test/java/dev/ebullient/convert/TestUtils.java b/src/test/java/dev/ebullient/convert/TestUtils.java index 1bf97ea44..5f0fd93ad 100644 --- a/src/test/java/dev/ebullient/convert/TestUtils.java +++ b/src/test/java/dev/ebullient/convert/TestUtils.java @@ -231,11 +231,16 @@ public static void commonTests(Path p, String l, List<String> errors) { errors.add(String.format("Found invalid dice roll in %s: %s", p, l)); } } + // Alarm is a basic spell. It should always be linked. If it isn't, // a reference has gone awry somewhere along the way if (p.toString().contains("list-spells-") && l.contains(" Alarm")) { errors.add(String.format("Missing link to Alarm spell in %s: %s", p, l)); } + + if (l.contains("NOT_FOUND")) { + errors.add(String.format("Found NOT_FOUND in %s: %s", p, l)); + } } /** @@ -353,6 +358,43 @@ static List<String> checkDirectoryContents(Path directory, Tui tui, return errors; } + public static List<String> yamlStatblockChecker(Path p, List<String> content) { + List<String> errors = new ArrayList<>(); + boolean found = false; + boolean yaml = false; + boolean index = false; + List<String> statblock = new ArrayList<>(); + + for (String l : content) { + if (l.startsWith("# Index ")) { + index = true; + } else if (l.equals("```statblock")) { + found = yaml = true; // start yaml block + } else if (l.equals("```")) { + yaml = false; // end yaml block + } else if (yaml) { + statblock.add(l); + if (l.contains("*")) { + errors.add(String.format("Found '*' in %s: %s", p, l)); + } + if (l.contains("\"desc\": \"\"")) { + errors.add(String.format("Found empty description in %s: %s", p, l)); + } + } + TestUtils.commonTests(p, l, errors); + } + + try { + Tui.quotedYaml().load(String.join("\n", statblock)); + } catch (Exception e) { + errors.add(String.format("File %s contains invalid yaml: %s", p, e)); + } + if (!found && !index) { + errors.add(String.format("File %s did not contain a yaml statblock", p)); + } + return errors; + } + public static String dump(LaunchResult result) { return "\nSystem out:\n" + result.getOutput() + "\nSystem err:\n" + result.getErrorOutput(); diff --git a/src/test/java/dev/ebullient/convert/tools/dnd5e/CommonDataTests.java b/src/test/java/dev/ebullient/convert/tools/dnd5e/CommonDataTests.java index 046c3ed50..cfa51124f 100644 --- a/src/test/java/dev/ebullient/convert/tools/dnd5e/CommonDataTests.java +++ b/src/test/java/dev/ebullient/convert/tools/dnd5e/CommonDataTests.java @@ -377,42 +377,7 @@ public void testMonsterYamlBody(Path outputPath) { Path undead = out.resolve(index.compendiumFilePath()).resolve(Tools5eQuteBase.monsterPath(false, "undead")); assertThat(undead).exists(); - TestUtils.assertDirectoryContents(undead, tui, (p, content) -> { - List<String> errors = new ArrayList<>(); - boolean found = false; - boolean yaml = false; - boolean index = false; - List<String> statblock = new ArrayList<>(); - - for (String l : content) { - if (l.startsWith("# Index ")) { - index = true; - } else if (l.equals("```statblock")) { - found = yaml = true; // start yaml block - } else if (l.equals("```")) { - yaml = false; // end yaml block - } else if (yaml) { - statblock.add(l); - if (l.contains("*")) { - errors.add(String.format("Found '*' in %s: %s", p, l)); - } - if (l.contains("\"desc\": \"\"")) { - errors.add(String.format("Found empty description in %s: %s", p, l)); - } - } - TestUtils.commonTests(p, l, errors); - } - - try { - Tui.quotedYaml().load(String.join("\n", statblock)); - } catch (Exception e) { - errors.add(String.format("File %s contains invalid yaml: %s", p, e)); - } - if (!found && !index) { - errors.add(String.format("File %s did not contain a yaml statblock", p)); - } - return errors; - }); + TestUtils.assertDirectoryContents(undead, tui, TestUtils::yamlStatblockChecker); } } diff --git a/src/test/java/dev/ebullient/convert/tools/pf2e/CommonDataTests.java b/src/test/java/dev/ebullient/convert/tools/pf2e/CommonDataTests.java index b4bfd2b16..4c0f79e73 100644 --- a/src/test/java/dev/ebullient/convert/tools/pf2e/CommonDataTests.java +++ b/src/test/java/dev/ebullient/convert/tools/pf2e/CommonDataTests.java @@ -37,6 +37,7 @@ public class CommonDataTests { enum TestInput { all, + yamlStatblocks, partial, none; } @@ -63,15 +64,16 @@ public CommonDataTests(TestInput variant) throws Exception { if (TestUtils.PATH_PF2E_TOOLS_DATA.toFile().exists()) { switch (variant) { - case all: - configurator.addSources(List.of("*")); - break; - case partial: - configurator.readConfiguration(TestUtils.TEST_RESOURCES.resolve("pf2e.json")); - break; - case none: - // should be default (CRD) - break; + case all -> configurator.addSources(List.of("*")); + case yamlStatblocks -> configurator.readConfiguration(TestUtils.TEST_RESOURCES.resolve("pf2e-yaml.json")); + case partial -> configurator.readConfiguration(TestUtils.TEST_RESOURCES.resolve("pf2e.json")); + // should be default (CRD) + case none -> { + } + } + + if (variant != TestInput.yamlStatblocks) { + templates.setCustomTemplates(TtrpgConfig.getConfig()); } for (String x : List.of("books.json", diff --git a/src/test/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonDataYamlStatblockTest.java b/src/test/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonDataYamlStatblockTest.java new file mode 100644 index 000000000..327bd09c6 --- /dev/null +++ b/src/test/java/dev/ebullient/convert/tools/pf2e/Pf2eJsonDataYamlStatblockTest.java @@ -0,0 +1,26 @@ +package dev.ebullient.convert.tools.pf2e; + +import java.nio.file.Path; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import dev.ebullient.convert.TestUtils; +import dev.ebullient.convert.tools.pf2e.CommonDataTests.TestInput; +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +public class Pf2eJsonDataYamlStatblockTest { + private static CommonDataTests commonTests; + + @BeforeAll + public static void setupDir() throws Exception { + commonTests = new CommonDataTests(TestInput.yamlStatblocks); + } + + @Test + public void testCreature_pf2e() { + Path dir = commonTests.generateNotesForType(Pf2eIndexType.creature); + + TestUtils.assertDirectoryContents(dir, commonTests.tui, TestUtils::yamlStatblockChecker); + } +} diff --git a/src/test/resources/pf2e-yaml.json b/src/test/resources/pf2e-yaml.json new file mode 100644 index 000000000..ec1cd2c0d --- /dev/null +++ b/src/test/resources/pf2e-yaml.json @@ -0,0 +1,5 @@ +{ + "from": ["*"], + "useDiceRoller": true, + "yamlStatblocks": true +} From b0c0bb8ed4d9d3d10cf47e987b850903f5c3f8a8 Mon Sep 17 00:00:00 2001 From: miscoined <miscoined@gmail.com> Date: Tue, 9 Jul 2024 14:16:59 +1000 Subject: [PATCH 19/25] =?UTF-8?q?=F0=9F=9A=B8=20Add=20extension=20method?= =?UTF-8?q?=20helpers=20for=20newlines=20and=20quoting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add a method to unfold newlines for use with specific YAML multiline string syntax - Add a method to quote YAML strings only when necessary --- .../convert/qute/TtrpgTemplateExtension.java | 41 +++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/src/main/java/dev/ebullient/convert/qute/TtrpgTemplateExtension.java b/src/main/java/dev/ebullient/convert/qute/TtrpgTemplateExtension.java index 014a39e35..4f7e5b1f0 100644 --- a/src/main/java/dev/ebullient/convert/qute/TtrpgTemplateExtension.java +++ b/src/main/java/dev/ebullient/convert/qute/TtrpgTemplateExtension.java @@ -7,6 +7,7 @@ import dev.ebullient.convert.StringUtil; import dev.ebullient.convert.io.JavadocVerbatim; +import dev.ebullient.convert.config.TtrpgConfig; import io.quarkus.qute.TemplateExtension; /** @@ -31,7 +32,6 @@ static String capitalized(String s) { /** * Return the string pluralized based on the size of the collection. - * * Example: `{resource.name.pluralized(resource.components)}` */ @JavadocVerbatim @@ -54,7 +54,6 @@ static String prefixSpace(Object obj) { /** * Return the given collection converted into a string and joined using the specified joiner. - * * Example: `{resource.components.join(", ")}` */ @JavadocVerbatim @@ -64,11 +63,47 @@ static String join(Collection<?> collection, String joiner) { /** * Return the given list joined into a single string, using a different delimiter for the last element. - * * Example: `{resource.components.joinConjunct(", ", " or ")}` */ @JavadocVerbatim static String joinConjunct(Collection<?> collection, String joiner, String lastjoiner) { return StringUtil.joinConjunct(joiner, lastjoiner, collection.stream().map(o -> o.toString()).toList()); } + + /** Indent each line of the given string with the given indent. */ + static String indent(String lines, String indent) { + return lines.replaceAll("\n", "\n" + indent); + } + + /** + * Double all newlines in the text (eg replace every newline with two newlines). For use with embedded YAML, where the + * {@code >} folding operator will ignore newlines that aren't 'doubled'. This only replaces single newlines, not newlines + * that are already doubled. + */ + static String unfoldNewlines(String text) { + return text.replaceAll("([^\n])\n([^\n])", "$1\n\n$2"); + } + + /** + * Quote the input according to YAML property rules. Only quote if necessary for YAML to interpret it as a string. Escape + * quotes in the input string if necessary. + */ + static String quoted(Object obj) { + if (obj == null) { + return ""; + } + String text = obj.toString(); + if (text == null || text.isBlank()) { + return ""; + } + if (text.contains("\n")) { + TtrpgConfig.getConfig().tui().errorf("Asked to quote a multiline string: %s", text); + } + if (!text.startsWith("[") && !text.startsWith("*") && !text.contains(":") && !text.startsWith("\"")) { + // No quoting required + return text; + } + // Escape any quotes in the text before we quote it + return "\"%s\"".formatted(text.replaceAll("\"", "\\\\\"")); + } } From f0100cc6ad24e8dc2015f2db2b3f9fabe9690569 Mon Sep 17 00:00:00 2001 From: miscoined <miscoined@gmail.com> Date: Sun, 7 Jul 2024 22:02:11 +1000 Subject: [PATCH 20/25] =?UTF-8?q?=F0=9F=9A=A7=20Begin=20adding=20support?= =?UTF-8?q?=20for=20Pf2e=20fantasy=20statblock=20bestiary?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I've opted to use ** rather than __ for bold formatting in PF2e statblocks. This is primarily for consistency - we can't reliably change all instances of asterisk formatting within embedded text without risking changing asterisks which aren't formatting related, so we may as well double down on using asterisks for formatting since they're only reserved in specific contexts. --- .../pf2etools/creature2md-yamlStatblock.txt | 194 ++++++++++++++++++ .../convert/tools/pf2e/qute/QuteCreature.java | 25 +++ .../tools/pf2e/qute/QuteDataActivity.java | 26 ++- .../tools/pf2e/qute/QuteDataDefenses.java | 10 +- src/test/resources/pf2e-yaml.json | 5 +- 5 files changed, 249 insertions(+), 11 deletions(-) create mode 100644 examples/templates/pf2etools/creature2md-yamlStatblock.txt diff --git a/examples/templates/pf2etools/creature2md-yamlStatblock.txt b/examples/templates/pf2etools/creature2md-yamlStatblock.txt new file mode 100644 index 000000000..c1d7d6db8 --- /dev/null +++ b/examples/templates/pf2etools/creature2md-yamlStatblock.txt @@ -0,0 +1,194 @@ +{#with resource} +--- +obsidianUIMode: preview +cssclasses: pf2e,pf2e-creature +statblock: inline +{#if tags} +tags: +{#each tags} +- {it} +{/each} +{/if} +{#if aliases} +aliases: +{#each aliases} +- {it} +{/each} +{/if} +--- +# {name} *Creature {level}* +{traits join " "} + +```statblock +layout: Pathfinder 2e Creature Layout +source: {sources.primarySource.quoted} +sourcebook: {source.quoted} +name: {name.quoted} +level: Creature {level} + +{#let alignment=traits.getFirst("Alignment") rarity=traits.getFirst("Rarity") size=traits.getFirst("Size") genericTraits=traits.genericTraits} +{#if alignment} +alignment: {alignment.withoutTitle.quoted} +{/if}{#if rarity} +rarity: {rarity.withoutTitle.quoted} +{/if}{#if size} +size: {size.withoutTitle.quoted} +{/if}{#if genericTraits} +traits: + {#each genericTraits} + - {it.withoutTitle.quoted} + {/each} +{/if} +{/let} + +{#if perception} +modifier: {perception} +{/if}{#if senses} +senses: {senses.join(", ").quoted} +{/if}{#if languages} +languages: {languages.quoted} +{/if}{#if skills} +skills: + {#for skill in skills.skills} + - {skill.name.quoted}: {skill.value} + {#each skill.otherBonuses} + {it.key.quoted}: {it.value} + {/each} + {#if skill.notes} + note: {skill.formattedNotes} + {/if} + {/for} + {#if skills.notes} + - note: {skills.notes.join(", ").quoted} + {/if} +{/if}{#if abilityMods} +attributes: + {#each abilityMods} + - {it.key}: {it.value} + {/each} +{/if}{#if speed} +speed: {speed.quoted} +{/if} + +{#if defenses} +{#if defenses.ac} +ac: {defenses.ac.value} +{#if defenses.ac.formattedNotes} +acNote: {defenses.ac.formattedNotes.quoted} +{/if} +{/if} +{#if defenses.savingThrows} +saves: + {#for save in defenses.savingThrows.saves} + - {save.name.toLowerCase().quoted}: {save.value} + {#each save.otherBonuses} + {it.key.quoted}: {it.value} + {/each} + {#if save.notes} + note: {save.formattedNotes} + {/if} + {/for} + {#if defenses.savingThrows.abilities} + - note: {defenses.savingThrows.abilities.join(", ").quoted} + {/if} +{/if} +{#if defenses.hpHardnessBt} +{#if defenses.hpHardnessBt.hp} +hp: {defenses.hpHardnessBt.hp.value} +{/if} +{#if defenses.hpHardnessBt.hp.formattedNotes || defenses.additionalHp} +hpNote: "{defenses.hpHardnessBt.hp.formattedNotes}{#if defenses.additionalHp}; {defenses.additionalHp}{/if}" +{/if}{#if defenses.additionalHardness} +hardness: "{#if defenses.hpHardnessBt.hardness}{defenses.hpHardnessBt.hardness}; {/if}{defenses.additionalHardness}" +{#else if defenses.hpHardnessBt.hardness} +hardness: {defenses.hpHardnessBt.hardness} +{/if} +{/if} +{#if defenses.immunities} +immunities: "{#each defenses.immunities}{it.withoutTitle}{#if it_hasNext}, {/if}{/each}" +{/if}{#if defenses.resistances} +resistances: "{#each defenses.resistances}{it.key} {it.value}{#if it_hasNext}, {/if}{/each}" +{/if}{#if defenses.weaknesses} +weaknesses: "{#each defenses.weaknesses}{it.key} {it.value}{#if it_hasNext}, {/if}{/each}" +{/if} +{/if} + +{#if items} +items: {items.join(", ").quoted} +{/if} + +{#for abilitySet in abilities.abilityMap.orEmpty} +{#if abilitySet.value} +abilities_{abilitySet.key}: + {#each abilitySet.value} + - name: {it.name} + {#if it.isAbility} + desc: > + {it.activity.unicode}{#if it.traits || it.components} ({it.bareTraitsList}{#if it.bareTraitsList && it.components}, {/if}{resource.components.orEmpty join ", "}); + {#if it.range}__Range__ {it.range}; {/if} + {#if it.cost}__Cost__ {it.cost}; {/if} + {#if it.frequency}__Frequency__ {it.frequency}; {/if} + {#if it.trigger}__Trigger__ {it.trigger}; {/if} + {#if it.requirements}__Requirements__ {it.requirements}; {/if} + {#if it.prerequisites}__Prerequisites__ {it.prerequisites}; {/if} + {#if it.hasEffect} + {#if it.range || it.cost || it.frequency || it.requirements || it.prerequisites}__Effect__ {/if}{it.text} + {/if} + {/each} +{/if} +{/for} + +{#if attacks} +attacks: + {#each attacks} + - name: ___{it.rangeType}___ {it.activity.unicodeGlyphOrText} {it.name} + desc: ({it.traits join ", "}) + bonus: {it.attackBonus} + {#if it.multilineEffect} + damage: > + {it.damage}; {it.multilineEffect} + {#else} + damage: {it.damage} + {/if} + {/each} +{/if} + +{#if spellcasting} +spellcasting: +{#for spells in spellcasting} + - name: {spells.name.quoted} + {#if spells.dc} + dc: {spells.dc} + {/if}{#if spells.attackBonus} + bonus: {spells.attackBonus} + {/if}{#if spells.focusPoints} + fp: {spells.focusPoints} + {/if} + desc: > + {#if spells.notes}{spells.notes join ", "}; {/if}{#if spells.ranks}{spells.ranks join "; "};{/if} + {#each spells.constantRanks} + **Constant ({it.rank})** {it.spells join ", "}{#if it_hasNext}; {/if} + {/each} +{/for} +{#for rituals in ritualCasting} + - name: {rituals.name.quoted} + {#if rituals.dc} + dc: {rituals.dc} + {/if} + desc: > + {rituals.ranks.join("; ")} +{/for} +{/if} +``` +^statblock + +{#if hasSections && description} +## Summary +{/if}{#if description} +{description} +{/if}{#if text} +{text} +{/if} + +*Source: {source}* +{/with} diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteCreature.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteCreature.java index 6c931d926..90975c053 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteCreature.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteCreature.java @@ -95,6 +95,27 @@ public QuteCreature( this.ritualCasting = ritualCasting; } + /** Return the size of this creature, or null if it has none. */ + public String getSize() { + return traits.stream() + .filter(ref -> ref.title() != null && ref.title().contains("Size Trait")) + .findAny().map(QuteDataRef::displayText).orElse(null); + } + + /** The alignment of this creature, or null if it has none. */ + public String getAlignment() { + return traits.stream() + .filter(ref -> ref.title() != null && ref.title().contains("Alignment Trait")) + .findAny().map(QuteDataRef::displayText).orElse(null); + } + + /** The rarity of this creature, or null if it has none. */ + public String getRarity() { + return traits.stream() + .filter(ref -> ref.title() != null && ref.title().contains("Rarity Trait")) + .findAny().map(QuteDataRef::displayText).orElse(null); + } + /** * The languages and language features known by a creature. Example default output: * `Common, Sylvan; telepathy 100ft; knows any language the summoner does` @@ -182,6 +203,10 @@ public record CreatureAbilities( List<QuteAbilityOrAffliction> top, List<QuteAbilityOrAffliction> middle, List<QuteAbilityOrAffliction> bottom) implements QuteUtil { + /** Return abilities as a map. */ + public Map<String, List<QuteAbilityOrAffliction>> getAbilityMap() { + return Map.of("top", top, "mid", middle, "bot", bottom); + } } /** diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataActivity.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataActivity.java index 94fa2d200..f442dacbc 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataActivity.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataActivity.java @@ -28,26 +28,36 @@ public String text() { return isPresent(note) ? note : activity.longName; } + /** + * Return the single-character Pathfinder 2e font unicode glyph used to represent this action, or if there is no single + * character (eg for varies and duration activities), return {@link QuteDataActivity#text()}. + */ + public String getUnicodeGlyphOrText() { + return activity.unicodeChar != null ? activity.unicodeChar.toString() : text(); + } + @Override public String toString() { return join(" ", actionRef.toString(), note); } public enum Activity { - single("Single Action", ">"), - two("Two-Action", ">>"), - three("Three-Action", ">>>"), - free("Free Action", "F"), - reaction("Reaction", "R"), - varies("Varies", "V"), - timed("Duration or Frequency", "⏲"); + single("Single Action", ">", '⬻'), + two("Two-Action", ">>", '⬺'), + three("Three-Action", ">>>", '⬽'), + free("Free Action", "F", '⭓'), + reaction("Reaction", "R", '⬲'), + varies("Varies", "V", null), + timed("Duration or Frequency", "⏲", null); public final String longName; public final String textGlyph; + public final Character unicodeChar; - Activity(String longName, String textGlyph) { + Activity(String longName, String textGlyph, Character unicodeChar) { this.longName = longName; this.textGlyph = textGlyph; + this.unicodeChar = unicodeChar; } } } diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataDefenses.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataDefenses.java index 5080e16ea..7ba14b272 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataDefenses.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteDataDefenses.java @@ -52,7 +52,7 @@ public record QuteDataDefenses( Map<String, QuteDataGenericStat> weaknesses) implements QuteUtil { @SuppressWarnings("unused") // for template use - public String additionalHp() { + public String getAdditionalHp() { return additionalHpHardnessBt.entrySet().stream() .filter(e -> e.getValue().hp() != null) .map(e -> "__%s HP__ %s".formatted(e.getKey(), e.getValue().hp())) @@ -60,7 +60,7 @@ public String additionalHp() { } @SuppressWarnings("unused") // for template use - public String additionalHardness() { + public String getAdditionalHardness() { return additionalHpHardnessBt.entrySet().stream() .filter(e -> e.getValue().hardness() != null) .map(e -> "__%s Hardness__ %s".formatted(e.getKey(), e.getValue().hardness())) @@ -101,6 +101,12 @@ public String toString() { public record QuteSavingThrows( QuteDataNamedBonus fort, QuteDataNamedBonus ref, QuteDataNamedBonus will, List<String> abilities) implements QuteUtil { + + /** Return the saves as a list of {@link QuteDataGenericStat.QuteDataNamedBonus}. */ + public List<QuteDataNamedBonus> getSaves() { + return List.of(fort, ref, will); + } + /** Returns all abilities as a formatted, comma-separated string. */ public String formattedAbilities() { return join(", ", abilities); diff --git a/src/test/resources/pf2e-yaml.json b/src/test/resources/pf2e-yaml.json index ec1cd2c0d..3d1bece9f 100644 --- a/src/test/resources/pf2e-yaml.json +++ b/src/test/resources/pf2e-yaml.json @@ -1,5 +1,8 @@ { "from": ["*"], "useDiceRoller": true, - "yamlStatblocks": true + "yamlStatblocks": true, + "template": { + "creature" : "examples/templates/pf2etools/creature2md-yamlStatblock.txt" + } } From 8dd89f3a54e1d9a0f32519b6bc15b7a1fe0d7120 Mon Sep 17 00:00:00 2001 From: miscoined <miscoined@gmail.com> Date: Sun, 7 Jul 2024 21:44:35 +1000 Subject: [PATCH 21/25] =?UTF-8?q?=F0=9F=A7=B1=20Add=20an=20asYamlStatblock?= =?UTF-8?q?=20parameter=20for=20embedded=20templates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Strip dice roller syntax from embedded yaml templates --- .../java/dev/ebullient/convert/io/Templates.java | 3 ++- src/main/java/dev/ebullient/convert/io/Tui.java | 4 ++-- .../java/dev/ebullient/convert/qute/QuteUtil.java | 15 ++++++++++++++- .../convert/tools/JsonTextConverter.java | 9 +++++---- .../ebullient/convert/tools/dnd5e/JsonSource.java | 2 +- .../convert/tools/pf2e/Json2QuteArchetype.java | 2 +- .../ebullient/convert/tools/pf2e/JsonSource.java | 2 +- .../convert/tools/pf2e/qute/QuteAbility.java | 4 ++-- .../convert/tools/pf2e/qute/QuteAffliction.java | 4 ++-- .../convert/tools/pf2e/qute/QuteInlineAttack.java | 4 ++-- 10 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/main/java/dev/ebullient/convert/io/Templates.java b/src/main/java/dev/ebullient/convert/io/Templates.java index d2c127cba..87d0fbf22 100644 --- a/src/main/java/dev/ebullient/convert/io/Templates.java +++ b/src/main/java/dev/ebullient/convert/io/Templates.java @@ -78,11 +78,12 @@ public String render(QuteBase resource) { } } - public String renderInlineEmbedded(QuteUtil resource) { + public String renderInlineEmbedded(QuteUtil resource, boolean asYamlStatblock) { Template tpl = customTemplateOrDefault(resource.template()); try { return tpl .data("resource", resource) + .data("asYamlStatblock", asYamlStatblock) .render().trim(); } catch (TemplateException tex) { Throwable cause = tex.getCause(); diff --git a/src/main/java/dev/ebullient/convert/io/Tui.java b/src/main/java/dev/ebullient/convert/io/Tui.java index 2ab66d554..dd8e234b3 100644 --- a/src/main/java/dev/ebullient/convert/io/Tui.java +++ b/src/main/java/dev/ebullient/convert/io/Tui.java @@ -605,8 +605,8 @@ public void writeYamlFile(Path outputFile, Object obj) throws IOException { yamlMapper().writer().writeValue(outputFile.toFile(), obj); } - public String renderEmbedded(QuteUtil resource) { - return templates.renderInlineEmbedded(resource); + public String renderEmbedded(QuteUtil resource, boolean asYamlStatblock) { + return templates.renderInlineEmbedded(resource, asYamlStatblock); } public <T> T readJsonValue(JsonNode node, TypeReference<T> targetRef) { diff --git a/src/main/java/dev/ebullient/convert/qute/QuteUtil.java b/src/main/java/dev/ebullient/convert/qute/QuteUtil.java index 0bbd42c8d..a629ec75e 100644 --- a/src/main/java/dev/ebullient/convert/qute/QuteUtil.java +++ b/src/main/java/dev/ebullient/convert/qute/QuteUtil.java @@ -96,6 +96,19 @@ default IndexType indexType() { @JavadocIgnore interface Renderable { /** Return this object rendered using its template. */ - String render(); + String render(boolean asYamlStatblock); + + /** Return the object rendered using its template. */ + default String render() { + return render(false); + } + + /** Return the object rendered using its template with {@code asYamlStatblock} set to true. */ + default String renderAsYamlStatblock() { + // Manually remove the dice roller syntax - the yaml statblocks handle dice roller syntax differently. At this + // point, the parsing has already finished, so we can't use parseState to stop them from being added in the first + // place. So all we can do is post-process to remove them again. + return render(true).replaceAll("`dice: [^`]+` \\(`([^`]+)`\\)", "$1"); + } } } diff --git a/src/main/java/dev/ebullient/convert/tools/JsonTextConverter.java b/src/main/java/dev/ebullient/convert/tools/JsonTextConverter.java index 2522a3f44..ad940ce45 100644 --- a/src/main/java/dev/ebullient/convert/tools/JsonTextConverter.java +++ b/src/main/java/dev/ebullient/convert/tools/JsonTextConverter.java @@ -495,9 +495,9 @@ default List<String> removePreamble(List<String> content) { * @param resource QuteBase containing required template resource data * @param admonition Type of embedded/encapsulating admonition */ - default String renderEmbeddedTemplate(QuteUtil resource, String admonition, String... prepend) { + default String renderEmbeddedTemplate(QuteUtil resource, String admonition, boolean asYamlStatblock, String... prepend) { List<String> inner = new ArrayList<>(); - renderEmbeddedTemplate(inner, resource, admonition, prepend); + renderEmbeddedTemplate(inner, resource, admonition, asYamlStatblock, prepend); return String.join("\n", inner); } @@ -509,10 +509,11 @@ default String renderEmbeddedTemplate(QuteUtil resource, String admonition, Stri * @param admonition Type of embedded/encapsulating admonition * @param prepend Text to prepend at beginning of admonition (e.g. title) */ - default void renderEmbeddedTemplate(List<String> text, QuteUtil resource, String admonition, String... prepend) { + default void renderEmbeddedTemplate( + List<String> text, QuteUtil resource, String admonition, boolean asYamlStatblock, String... prepend) { Boolean pushed = (resource instanceof QuteBase) ? parseState().push(((QuteBase)resource).sources()) : null; try { - String rendered = tui().renderEmbedded(resource); + String rendered = tui().renderEmbedded(resource, asYamlStatblock); List<String> inner = new ArrayList<>(Arrays.asList(prepend)); inner.addAll(removePreamble(new ArrayList<>(List.of(rendered.split("\n"))))); diff --git a/src/main/java/dev/ebullient/convert/tools/dnd5e/JsonSource.java b/src/main/java/dev/ebullient/convert/tools/dnd5e/JsonSource.java index 7d638202a..b8fe53a75 100644 --- a/src/main/java/dev/ebullient/convert/tools/dnd5e/JsonSource.java +++ b/src/main/java/dev/ebullient/convert/tools/dnd5e/JsonSource.java @@ -605,7 +605,7 @@ default void appendStatblockInline(List<String> text, JsonNode entry, String hea .withTargetFile(embedFileName) .withTargetPath(relativePath)); } else { - renderEmbeddedTemplate(text, qs, type.name(), + renderEmbeddedTemplate(text, qs, type.name(), false, "title: " + name, "collapse: closed", existingNode == null ? "" : "%% See " + type.linkify(this, data) + " %%"); diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteArchetype.java b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteArchetype.java index cffc2418b..55dd5cf6c 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteArchetype.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/Json2QuteArchetype.java @@ -112,7 +112,7 @@ QuteFeat findFeat(String levelKey) { } String render(QuteFeat quteFeat, boolean archetypeFeat) { - return renderEmbeddedTemplate(quteFeat, "feat", + return renderEmbeddedTemplate(quteFeat, "feat", false, "title: %s, Feat %s".formatted(quteFeat.getName(), quteFeat.level + (archetypeFeat ? "*" : "")), "collapse: closed"); } diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java b/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java index 00aeb0c9f..b613e99fc 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/JsonSource.java @@ -551,7 +551,7 @@ default void embedData(List<String> text, JsonNode dataNode) { // and add the collapsible admonition ourselves Pf2eQuteBase converted = dataType.convertJson2QuteBase(index(), data); if (converted != null) { - renderEmbeddedTemplate(text, converted, tag, + renderEmbeddedTemplate(text, converted, tag, false, "title: %s".formatted(converted.title()), "collapse: closed"); } else { diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAbility.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAbility.java index 0279d2927..d3ef01e9e 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAbility.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAbility.java @@ -143,7 +143,7 @@ public String toString() { } @Override - public String render() { - return _converter.renderEmbeddedTemplate(this, null); + public String render(boolean asYamlStatblock) { + return _converter.renderEmbeddedTemplate(this, null, asYamlStatblock); } } diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAffliction.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAffliction.java index 35d192f10..b8665ac8a 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAffliction.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAffliction.java @@ -95,8 +95,8 @@ public String template() { } @Override - public String render() { - return _converter.renderEmbeddedTemplate(this, null); + public String render(boolean asYamlStatblock) { + return _converter.renderEmbeddedTemplate(this, null, asYamlStatblock); } @Override diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteInlineAttack.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteInlineAttack.java index be6796816..a36258a09 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteInlineAttack.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteInlineAttack.java @@ -105,8 +105,8 @@ public String template() { } @Override - public String render() { - return _converter.renderEmbeddedTemplate(this, null); + public String render(boolean asYamlStatblock) { + return _converter.renderEmbeddedTemplate(this, null, asYamlStatblock); } @Override From 50c70e26a3fffe0ee18d07a0efa107000eedba03 Mon Sep 17 00:00:00 2001 From: miscoined <miscoined@gmail.com> Date: Sun, 7 Jul 2024 21:44:35 +1000 Subject: [PATCH 22/25] =?UTF-8?q?=F0=9F=9A=B8=F0=9F=92=A5=20Add=20embedded?= =?UTF-8?q?=20YAML=20templates=20for=20abilities?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 💥 Remove, rename, and change QuteAbility methods to better suit the data - 🚸 Add an asYamlStatblock section to the default template for YAML ability statblock rendering --- .../pf2etools/creature2md-yamlStatblock.txt | 16 +--- .../convert/tools/pf2e/qute/QuteAbility.java | 27 +++---- .../templates/toolsPf2e/ability2md.txt | 3 +- .../templates/toolsPf2e/inline-ability2md.txt | 76 ++++++++++++------- 4 files changed, 61 insertions(+), 61 deletions(-) diff --git a/examples/templates/pf2etools/creature2md-yamlStatblock.txt b/examples/templates/pf2etools/creature2md-yamlStatblock.txt index c1d7d6db8..9cfe6b4b0 100644 --- a/examples/templates/pf2etools/creature2md-yamlStatblock.txt +++ b/examples/templates/pf2etools/creature2md-yamlStatblock.txt @@ -121,19 +121,9 @@ items: {items.join(", ").quoted} {#if abilitySet.value} abilities_{abilitySet.key}: {#each abilitySet.value} - - name: {it.name} - {#if it.isAbility} - desc: > - {it.activity.unicode}{#if it.traits || it.components} ({it.bareTraitsList}{#if it.bareTraitsList && it.components}, {/if}{resource.components.orEmpty join ", "}); - {#if it.range}__Range__ {it.range}; {/if} - {#if it.cost}__Cost__ {it.cost}; {/if} - {#if it.frequency}__Frequency__ {it.frequency}; {/if} - {#if it.trigger}__Trigger__ {it.trigger}; {/if} - {#if it.requirements}__Requirements__ {it.requirements}; {/if} - {#if it.prerequisites}__Prerequisites__ {it.prerequisites}; {/if} - {#if it.hasEffect} - {#if it.range || it.cost || it.frequency || it.requirements || it.prerequisites}__Effect__ {/if}{it.text} - {/if} + {#if it.isAbility} + {it.renderAsYamlStatblock indent " "} + {/if} {/each} {/if} {/for} diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAbility.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAbility.java index d3ef01e9e..ca941b17a 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAbility.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteAbility.java @@ -88,28 +88,24 @@ public QuteAbility(Pf2eSources sources, String name, String reference, List<Stri this._converter = converter; } - /** True if an activity (with text), components, or traits are present. */ - public boolean getHasActivity() { - return activity != null || isPresent(components) || isPresent(traits); - } - /** - * True if hasActivity is true, hasEffect is true or cost is present. - * In other words, this is true if a list of attributes could have been rendered. + * True if we have any details other than an activity, an effect, and components. e.g. if we have a cost, range, + * requirements, prerequisites, trigger, frequency, or special. * - * Use this to test for the end of those attributes (add whitespace or a special - * character ahead of ability text) + * <p>Use this to test for the end of those attributes (e.g. to add whitespace or a special + * character ahead of ability text)</p> */ public boolean getHasAttributes() { - return getHasActivity() || getHasEffect() || isPresent(cost); + return isPresent(range) || isPresent(requirements) || isPresent(prerequisites) || isPresent(cost) + || isPresent(trigger) || isPresent(frequency) || isPresent(special) || isPresent(note); } /** - * True if the ability is a short, one-line name and description. + * False if the ability is a short, one-line name and description. * Use this to test to choose between a detailed or simple rendering. */ public boolean getHasDetails() { - return getHasAttributes() || isPresent(special) || text.contains("\n") || text.split(" ").length > 5; + return getHasAttributes() || text.contains("\n") || text.split(" ").length > 5; } @Deprecated @@ -117,18 +113,13 @@ public boolean getHasBullets() { return getHasAttributes(); } - /** True if frequency, trigger, and requirements are present. In other words, this is true if the ability has an effect. */ - public boolean getHasEffect() { - return isPresent(frequency) || isPresent(trigger) || isPresent(requirements); - } - /** Return a comma-separated list of de-styled trait links (no title attributes) */ public String getBareTraitList() { if (traits == null || traits.isEmpty()) { return ""; } return traits.stream() - .map(ref -> new QuteDataRef(ref.displayText(), ref.notePath(), null).toString()) + .map(QuteDataRef::withoutTitle) .collect(Collectors.joining(", ")); } diff --git a/src/main/resources/templates/toolsPf2e/ability2md.txt b/src/main/resources/templates/toolsPf2e/ability2md.txt index 5b5a93a1c..ea5b04cae 100644 --- a/src/main/resources/templates/toolsPf2e/ability2md.txt +++ b/src/main/resources/templates/toolsPf2e/ability2md.txt @@ -26,9 +26,8 @@ aliases: ["{resource.name}"] - **Requirements**: {resource.requirements} {/if}{#if resource.prerequisites} - **Prerequisites**: {resource.prerequisites} -{/if}{#if resource.hasAttributes} +{/if}{#if resource.activity || resource.hasAttributes} -{/if}{#if resource.hasEffect} **Effect** {/if}{resource.text} {#if resource.special} diff --git a/src/main/resources/templates/toolsPf2e/inline-ability2md.txt b/src/main/resources/templates/toolsPf2e/inline-ability2md.txt index 15d46b3db..371486d8d 100644 --- a/src/main/resources/templates/toolsPf2e/inline-ability2md.txt +++ b/src/main/resources/templates/toolsPf2e/inline-ability2md.txt @@ -1,37 +1,57 @@ -{#let componentsTraits = (resource.components.join(", ") + (resource.components && resource.traits ? " " : "") + (resource.traits ? (str:format("(%s)", resource.traits.formattedWithoutTitles)) : ""))} -```ad-embed-ability -{#if resource.hasDetails } -title: **{#if resource.reference}{resource.reference}{#else}{resource.name}{/if}** {resource.activity}{componentsTraits.prefixSpace} -{#if resource.note} +{#with resource} +{#let componentsTraits = (components.join(", ") + (components && traits ? " " : "") + (traits ? (str:format("(%s)", bareTraitList)) : ""))} +{#if asYamlStatblock} +- name: {reference.or(name).quoted} +{#if hasDetails && hasAttributes} + desc: >{#if activity || componentsTraits} + {activity.unicodeGlyphOrText ?: ""}{activity && componentsTraits ? " " : ""}{componentsTraits}{#if components && !traits};{/if}{/if}{#if range} + **Range** {range};{/if}{#if cost} + **Cost** {cost};{/if}{#if frequency} + **Frequency** {frequency};{/if}{#if trigger} + **Trigger** {trigger};{/if}{#if requirements} + **Requirements** {requirements};{/if}{#if prerequisites} + **Prerequisites** {prerequisites};{/if} + **Effect** {text.unfoldNewlines indent " "}{#if special}; **Special** {special}{/if} +{#else if hasDetails} + desc: > + {activity.unicodeGlyphOrText ?: ""}{activity && componentsTraits ? " " : ""}{#if activity || componentsTraits && text}{componentsTraits}{#if components && !traits};{/if} {/if}{text.unfoldNewlines indent " "} +{#else} + desc: "{activity.unicodeGlyphOrText ?: ""}{activity && componentsTraits ? " " : ""}{componentsTraits}{#if activity || componentsTraits && text}{componentsTraits}{#if components && !traits};{/if} {/if}{text}" +{/if} +{#else} +{#if hasDetails} +title: **{reference ?: name}**{#if activity} {activity}{/if}{componentsTraits.prefixSpace} +{#if note} > [!pf2-note] -> {resource.note} -{/if}{#if resource.range} -- **Range**: {resource.range} -{/if}{#if resource.cost} -- **Cost**: {resource.cost} -{/if}{#if resource.frequency} -- **Frequency**: {resource.frequency} -{/if}{#if resource.trigger} -- **Trigger**: {resource.trigger} -{/if}{#if resource.requirements} -- **Requirements**: {resource.requirements} -{/if}{#if resource.prerequisites} -- **Prerequisites**: {resource.prerequisites} -{/if}{#if resource.hasAttributes} +> {note} +{/if}{#if range} +- **Range**: {range} +{/if}{#if cost} +- **Cost**: {cost} +{/if}{#if frequency} +- **Frequency**: {frequency} +{/if}{#if trigger} +- **Trigger**: {trigger} +{/if}{#if requirements} +- **Requirements**: {requirements} +{/if}{#if prerequisites} +- **Prerequisites**: {prerequisites} +{/if}{#if hasAttributes} -{/if}{#if resource.hasEffect} -**Effect** {/if}{resource.text} -{#if resource.special} +**Effect** {/if}{text} +{#if special} -**Special**: {resource.special} -{/if}{#if resource.source || resource.tags} +**Special**: {special} +{/if}{#if source || tags} %% -{#if resource.source} -Source: {resource.source}* +{#if source} +Source: {source}* {/if} -{#each resource.tags} #{it} {/each} +{#each tags} #{it} {/each} %%{/if} {#else} -title: **{resource.name}** {resource.text} +title: **{reference ?: name}**{#if activity} {activity}{/if}{componentsTraits.prefixSpace}{#if componentsTraits};{/if} {text} {/if} ``` +{/if} +{/with} From 32d09e2c5e0adc05341b656f40102fd06997b020 Mon Sep 17 00:00:00 2001 From: miscoined <miscoined@gmail.com> Date: Mon, 8 Jul 2024 16:58:45 +1000 Subject: [PATCH 23/25] =?UTF-8?q?=F0=9F=9A=B8=20Add=20YAML=20statblock=20r?= =?UTF-8?q?endering=20for=20attacks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pf2etools/creature2md-yamlStatblock.txt | 14 ++------- .../templates/toolsPf2e/inline-attack2md.txt | 31 ++++++++++++++----- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/examples/templates/pf2etools/creature2md-yamlStatblock.txt b/examples/templates/pf2etools/creature2md-yamlStatblock.txt index 9cfe6b4b0..913aeec49 100644 --- a/examples/templates/pf2etools/creature2md-yamlStatblock.txt +++ b/examples/templates/pf2etools/creature2md-yamlStatblock.txt @@ -130,17 +130,9 @@ abilities_{abilitySet.key}: {#if attacks} attacks: - {#each attacks} - - name: ___{it.rangeType}___ {it.activity.unicodeGlyphOrText} {it.name} - desc: ({it.traits join ", "}) - bonus: {it.attackBonus} - {#if it.multilineEffect} - damage: > - {it.damage}; {it.multilineEffect} - {#else} - damage: {it.damage} - {/if} - {/each} +{#each attacks} + {it.renderAsYamlStatblock indent " "} +{/each} {/if} {#if spellcasting} diff --git a/src/main/resources/templates/toolsPf2e/inline-attack2md.txt b/src/main/resources/templates/toolsPf2e/inline-attack2md.txt index a5d9b4a77..394c8c817 100644 --- a/src/main/resources/templates/toolsPf2e/inline-attack2md.txt +++ b/src/main/resources/templates/toolsPf2e/inline-attack2md.txt @@ -1,13 +1,28 @@ -{#let r=resource} -{#if r.multilineEffect} +{#with resource} +{#if asYamlStatblock} +- name: ___{rangeType}___ {activity.unicodeGlyphOrText} {name} + {#if traits} + desc: ({traits.formattedWithoutTitles}) + {/if} + bonus: {attackBonus} + {#if multilineEffect} + damage: > + {damage}; {multilineEffect.unfoldNewlines indent " "} + {#else} + damage: {damage.quoted} + {/if} +{#else} +{#if multilineEffect} ```ad-inline-attack -title: {r.rangeType} {r.activity} {r.name.capitalized}{r.bonus.prefixSpace}{#if r.traits} ({r.traits}){/if} -{#if r.damage} -**Damage** {r.damage} -{/if}{#if r.multilineEffect} -**Effect** {r.multilineEffect} +title: {rangeType} {activity} {name.capitalized}{bonus.prefixSpace}{#if traits} ({traits}){/if} +{#if damage} +**Damage** {damage} +{/if}{#if multilineEffect} +**Effect** {multilineEffect} {/if} ``` {#else} -- **{r.rangeType}** {r.activity} {r.name}{r.bonus.prefixSpace}{#if r.traits} ({r.traits}){/if}{#if r.damage}, **Damage** {r.damage}{/if} +- **{rangeType}** {activity} {name}{bonus.prefixSpace}{#if traits} ({traits}){/if}{#if damage}, **Damage** {damage}{/if} +{/if} {/if} +{/with} From b8e2dde8ab10c397d6479efb1d4a5efeefc58b72 Mon Sep 17 00:00:00 2001 From: miscoined <miscoined@gmail.com> Date: Tue, 9 Jul 2024 14:16:59 +1000 Subject: [PATCH 24/25] =?UTF-8?q?=F0=9F=9A=B8=20Add=20some=20workarounds?= =?UTF-8?q?=20and=20post-processing=20for=20YAML=20statblocks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Change tests to be more specific about which asterisks are disallowed - Add some workarounds for specific statblocks --- .../java/dev/ebullient/convert/qute/QuteUtil.java | 12 ++++++++---- .../convert/tools/pf2e/qute/QuteCreature.java | 5 +++++ src/test/java/dev/ebullient/convert/TestUtils.java | 12 +++++++++++- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/main/java/dev/ebullient/convert/qute/QuteUtil.java b/src/main/java/dev/ebullient/convert/qute/QuteUtil.java index a629ec75e..8d25ac64c 100644 --- a/src/main/java/dev/ebullient/convert/qute/QuteUtil.java +++ b/src/main/java/dev/ebullient/convert/qute/QuteUtil.java @@ -105,10 +105,14 @@ default String render() { /** Return the object rendered using its template with {@code asYamlStatblock} set to true. */ default String renderAsYamlStatblock() { - // Manually remove the dice roller syntax - the yaml statblocks handle dice roller syntax differently. At this - // point, the parsing has already finished, so we can't use parseState to stop them from being added in the first - // place. So all we can do is post-process to remove them again. - return render(true).replaceAll("`dice: [^`]+` \\(`([^`]+)`\\)", "$1"); + return render(true) + // Manually remove the dice roller syntax - the yaml statblocks handle dice roller syntax differently. At this + // point, the parsing has already finished, so we can't use parseState to stop them from being added in the + // first place. So all we can do is post-process to remove them again. + .replaceAll("`dice: [^`]+` \\(`([^`]+)`\\)", "$1") + // This usage is usually a footnote. With the Markdown rendering the asterisk is unnecessary, so just don't + // add the asterisk, so this doesn't get treated as Markdown formatting. + .replaceAll("\\* \\^\\[", " ^["); } } } diff --git a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteCreature.java b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteCreature.java index 90975c053..46dc498be 100644 --- a/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteCreature.java +++ b/src/main/java/dev/ebullient/convert/tools/pf2e/qute/QuteCreature.java @@ -362,6 +362,11 @@ public String formattedAmount() { @Override public String toString() { + if (notes.size() == 1 && notes.get(0).equals("*")) { + // Workaround for specific statblocks which use "*" to tag particular spells. Use a carat instead so it doesn't + // get Markdown formatted. + return join(" ", (spellRef == null ? name : spellRef.toString()) + "^", formattedAmount()); + } return join(" ", spellRef == null ? name : spellRef, formattedAmount(), formattedNotes()); } } diff --git a/src/test/java/dev/ebullient/convert/TestUtils.java b/src/test/java/dev/ebullient/convert/TestUtils.java index 5f0fd93ad..0b64dfd4f 100644 --- a/src/test/java/dev/ebullient/convert/TestUtils.java +++ b/src/test/java/dev/ebullient/convert/TestUtils.java @@ -48,6 +48,9 @@ public class TestUtils { static String GENERATED_DOCS = PROJECT_PATH.resolve("docs/templates").normalize().toAbsolutePath().toString(); + private static final Pattern ASTERISK_START_PROP_PAT = Pattern.compile(":\\s*\\*"); + private static final Pattern SINGLE_ASTERISK_PAT = Pattern.compile("[^*]\\*[^*]"); + // Obnoxious regular expression because markdown links are complicated: // Matches: [link text](vaultPath "title") // - link text is optional, and may contain parentheses. Use a negative lookahead for ]( @@ -374,7 +377,14 @@ public static List<String> yamlStatblockChecker(Path p, List<String> content) { yaml = false; // end yaml block } else if (yaml) { statblock.add(l); - if (l.contains("*")) { + // Asterisks at the start of values indicate aliases in YAML. If we find this, it's probably not intentional. + if (ASTERISK_START_PROP_PAT.matcher(l).matches()) { + errors.add(String.format("Found '*' property alias in %s: %s", p, l)); + } + // Sometimes statblock text uses asterisks. Double asterisks are usually intentional markdown, but single + // asterisks are suspect and may be asterisks which have snuck in from the data source, and won't be rendered + // literallywill be rendered. + if (SINGLE_ASTERISK_PAT.matcher(l).matches()) { errors.add(String.format("Found '*' in %s: %s", p, l)); } if (l.contains("\"desc\": \"\"")) { From 2730cd7cd4a396485f1b8f8d05e09d2fe3b62a23 Mon Sep 17 00:00:00 2001 From: miscoined <miscoined@gmail.com> Date: Tue, 9 Jul 2024 23:52:45 +1000 Subject: [PATCH 25/25] =?UTF-8?q?=F0=9F=9A=B8=20Add=20YAML=20statblock=20t?= =?UTF-8?q?emplate=20for=20afflictions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pf2etools/creature2md-yamlStatblock.txt | 2 - .../toolsPf2e/inline-affliction2md.txt | 55 ++++++++++++------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/examples/templates/pf2etools/creature2md-yamlStatblock.txt b/examples/templates/pf2etools/creature2md-yamlStatblock.txt index 913aeec49..46a5360d8 100644 --- a/examples/templates/pf2etools/creature2md-yamlStatblock.txt +++ b/examples/templates/pf2etools/creature2md-yamlStatblock.txt @@ -121,9 +121,7 @@ items: {items.join(", ").quoted} {#if abilitySet.value} abilities_{abilitySet.key}: {#each abilitySet.value} - {#if it.isAbility} {it.renderAsYamlStatblock indent " "} - {/if} {/each} {/if} {/for} diff --git a/src/main/resources/templates/toolsPf2e/inline-affliction2md.txt b/src/main/resources/templates/toolsPf2e/inline-affliction2md.txt index 7d45d370a..dcbed20e7 100644 --- a/src/main/resources/templates/toolsPf2e/inline-affliction2md.txt +++ b/src/main/resources/templates/toolsPf2e/inline-affliction2md.txt @@ -1,34 +1,47 @@ +{#with resource} +{#if asYamlStatblock} +- name: {name.quoted} + desc: > + ({#each traits}{it.withoutTitle}{#if it_hasNext}, {/if}{/each}){#if notes} {notes.join(", ")};{/if}{#if savingThrow} + **Saving Throw** {savingThrow};{/if}{#if onset} + **Onset** {onset};{/if}{#if maxDuration} + **Maximum Duration** {maxDuration};{/if}{#if effect} + **Effect** {effect};{/if} + {#each stages}**{it.key}** {it.value.text}{#if it.value.duration} ({it.value.duration}){/if}{#if it_hasNext}; {/if}{/each} +{#else} ````ad-inline-affliction -{#if resource.name} -title: {resource.name}{#if resource.formattedLevel} _{resource.formattedLevel}_{/if} +{#if name} +title: {name}{#if formattedLevel} _{formattedLevel}_{/if} {/if} -{#if resource.traits} -{#each resource.traits}{it} {/each} -{/if}{#if resource.text} -{resource.text} +{#if traits} +{#each traits}{it} {/each} +{/if}{#if text} +{text} -{/if}{#if resource.notes} -{#each resource.notes}{it}{#if it_hasNext}, {/if}{/each} +{/if}{#if notes} +{#each notes}{it}{#if it_hasNext}, {/if}{/each} -{/if}{#if resource.savingThrow} -- **Saving Throws**: {resource.savingThrow} -{/if}{#if resource.onset} -- **Onset**: {resource.onset} -{/if}{#if resource.maxDuration} -- **Maximum Duration**: {resource.maxDuration} -{/if}{#if resource.effect} +{/if}{#if savingThrow} +- **Saving Throws**: {savingThrow} +{/if}{#if onset} +- **Onset**: {onset} +{/if}{#if maxDuration} +- **Maximum Duration**: {maxDuration} +{/if}{#if effect} -**Effect** {resource.effect} -{/if}{#if resource.stages} +**Effect** {effect} +{/if}{#if stages} ## Stages -{#each resource.stages} +{#each stages} **{it.key}** {it.value.text}{#if it.value.duration } ({it.value.duration}){/if} {/each} -{/if}{#if resource.source} -*Source: {resource.source}* +{/if}{#if source} +*Source: {source}* {/if} -{#if resource.tags}%% {#each resource.tags}#{it} {/each}%%{/if} +{#if tags}%% {#each tags}#{it} {/each}%%{/if} ```` +{/if} +{/with}