Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/main/java/org/skdocs/skdocstool/Skdocstool.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ public void onEnable() {
public void onDisable() {
getLogger().info("Skdocstool has been disabled");
}
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
package org.skdocs.skdocstool.docs.addon;

import ch.njol.skript.lang.SyntaxElementInfo;
import ch.njol.skript.lang.SkriptEventInfo;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.skriptlang.skript.bukkit.registration.BukkitSyntaxInfos;
import org.skriptlang.skript.docs.Origin;
import org.skriptlang.skript.registration.SyntaxInfo;
import org.skdocs.skdocstool.docs.registration.LegacyEventAttribution;

public final class SyntaxOwnership {
private final List<AddonContext> addons;
private final ClassLoader coreLoader;
private final boolean explicitLegacyEventOrigins;

public SyntaxOwnership(List<AddonContext> addons, ClassLoader coreLoader) {
this(addons, coreLoader, LegacyEventAttribution.supported());
}

SyntaxOwnership(List<AddonContext> addons, ClassLoader coreLoader, boolean explicitLegacyEventOrigins) {
this.addons = List.copyOf(addons);
this.coreLoader = coreLoader;
this.explicitLegacyEventOrigins = explicitLegacyEventOrigins;
}

public boolean owns(SyntaxInfo<?> syntax, AddonContext addon) {
Expand All @@ -23,17 +31,20 @@ public boolean owns(SyntaxInfo<?> syntax, AddonContext addon) {

@SuppressWarnings("removal")
public AddonContext owner(SyntaxInfo<?> syntax) {
AddonContext declared = null;
if (syntax.origin() instanceof Origin.AddonOrigin origin) {
declared = addons.stream().filter(a -> a.addon().name().equals(origin.addon().name()))
.findFirst().orElse(null);
}
if (explicitLegacyEventOrigins && syntax instanceof SkriptEventInfo.ModernSkriptEventInfo<?>
&& declared != null) return declared;

Set<AddonContext> registered = new LinkedHashSet<>();
for (AddonContext addon : addons)
if (addon.registrationDocs().syntax(syntax.type(), syntax.patterns()) != null)
registered.add(addon);
if (registered.size() == 1) return registered.iterator().next();

AddonContext declared = null;
if (syntax.origin() instanceof Origin.AddonOrigin origin) {
declared = addons.stream().filter(a -> a.addon().name().equals(origin.addon().name()))
.findFirst().orElse(null);
}
if (!(syntax instanceof SyntaxElementInfo<?>) && declared != null) return declared;

if (syntax instanceof BukkitSyntaxInfos.Event<?> event) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.skdocs.skdocstool.docs.addon.AddonContext;
import org.skdocs.skdocstool.docs.addon.SyntaxOwnership;
import org.skdocs.skdocstool.docs.registration.RegistrationMetadata;
import org.skdocs.skdocstool.docs.registration.LegacyEventAttribution;
import org.skdocs.skdocstool.docs.builder.DocumentationFormat;
import org.skriptlang.skript.Skript;
import org.skriptlang.skript.bukkit.lang.eventvalue.EventValue;
Expand Down Expand Up @@ -115,7 +116,7 @@ private JsonArray eventsArray(AddonContext addon, SyntaxOwnership ownership, boo
obj.add("since", strings(since));
obj.add("requiredPlugins", strings(info.requiredPlugins()));
obj.add("keywords", strings(prefer(keywords, info.keywords().toArray(new String[0]))));
obj.addProperty("source", type.getName());
obj.addProperty("source", LegacyEventAttribution.source(info));
}

String[] eventValues = collectEventValues(info.events());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.skdocs.skdocstool.docs.registration;

import ch.njol.skript.lang.SkriptEventInfo;
import org.skriptlang.skript.bukkit.registration.BukkitSyntaxInfos;
import org.skriptlang.skript.docs.Origin;

@SuppressWarnings("removal")
public final class LegacyEventAttribution {
private static final boolean SUPPORTED = detectSupport();

private LegacyEventAttribution() {}

public static boolean supported() { return SUPPORTED; }

private static boolean detectSupport() {
try {
SkriptEventInfo.ModernSkriptEventInfo.class.getConstructor(
String.class, String[].class, Class.class, String.class, Class[].class, Origin.class);
return true;
} catch (NoSuchMethodException e) {
return false;
}
}

public static String source(BukkitSyntaxInfos.Event<?> event) {
return source(event, SUPPORTED);
}

static String source(BukkitSyntaxInfos.Event<?> event, boolean supported) {
if (supported && event instanceof SkriptEventInfo.ModernSkriptEventInfo<?> legacy) {
String path = legacy.getOriginClassPath();
if (path != null && !path.isBlank()) return path;
}
return event.type().getName();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,36 @@ class SyntaxOwnershipTest {
private final AddonContext core = addon("Engine", coreLoader);
private final Class<?> eventClass = eventClass();
private final AddonContext addon = addon("UnrelatedName", eventClass.getClassLoader());
private final SyntaxOwnership ownership = new SyntaxOwnership(List.of(core, addon), coreLoader);
private final SyntaxOwnership ownership = new SyntaxOwnership(List.of(core, addon), coreLoader, false);

@Test void fixedLegacyOriginWinsOverUnderlyingEventProvider() {
var resolver = new SyntaxOwnership(List.of(core, addon), coreLoader, true);
var event = legacyEvent();
assertSame(core, resolver.owner(event));
}

@Test void fixedLegacyAddonOriginWinsOverAnotherAddonsEvent() {
var registrar = addon("Registrar", new ClassLoader() {});
var resolver = new SyntaxOwnership(List.of(core, addon, registrar), coreLoader, true);
var event = legacyEvent();
when(event.origin()).thenReturn((Origin.AddonOrigin) () -> registrar.addon());
assertSame(registrar, resolver.owner(event));
}

@Test void fixedLegacyUnknownOriginStillUsesEventProvider() {
var resolver = new SyntaxOwnership(List.of(core, addon), coreLoader, true);
var event = legacyEvent();
when(event.origin()).thenReturn(Origin.UNKNOWN);
assertSame(addon, resolver.owner(event));
}

@Test void fixedLegacyOriginWinsOverScannedRegistrationMetadata() {
var resolver = new SyntaxOwnership(List.of(core, addon), coreLoader, true);
var event = legacyEvent();
addon.registrationDocs().putSyntax(SimpleEvent.class, new String[]{"signal"},
new RegistrationMetadata(null, "Signal", null, null, null, null, false));
assertSame(core, resolver.owner(event));
}

@Test void legacySharedSyntaxBelongsToTheUnderlyingEventProvider() {
var event = legacyEvent();
Expand Down Expand Up @@ -56,7 +85,7 @@ class SyntaxOwnershipTest {
@Test void ambiguousEventProvidersAreNotAssignedToCore() {
var otherClass = eventClass();
var other = addon("AnotherName", otherClass.getClassLoader());
var resolver = new SyntaxOwnership(List.of(core, addon, other), coreLoader);
var resolver = new SyntaxOwnership(List.of(core, addon, other), coreLoader, false);
var event = legacyEvent();
when(event.events()).thenReturn(List.of(eventClass, otherClass));
assertNull(resolver.owner(event));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.skdocs.skdocstool.docs.registration;

import ch.njol.skript.lang.SkriptEventInfo;
import ch.njol.skript.lang.util.SimpleEvent;
import org.junit.jupiter.api.Test;
import org.skriptlang.skript.bukkit.registration.BukkitSyntaxInfos;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

@SuppressWarnings({"removal", "unchecked"})
class LegacyEventAttributionTest {
@Test void sharedImplementationRetainsEachRegisteringClass() {
var first = legacy("example.First$Registration");
var second = legacy("example.Second");
assertEquals("example.First$Registration", LegacyEventAttribution.source(first, true));
assertEquals("example.Second", LegacyEventAttribution.source(second, true));
}

@Test void missingPathsFallBackToImplementation() {
for (String path : new String[]{null, "", " "})
assertEquals(SimpleEvent.class.getName(), LegacyEventAttribution.source(legacy(path), true));
}

@Test void olderSkriptDoesNotTrustLegacyPaths() {
assertEquals(SimpleEvent.class.getName(),
LegacyEventAttribution.source(legacy("Addon label"), false));
}

@Test void modernEventsKeepImplementationSource() {
var modern = mock(BukkitSyntaxInfos.Event.class);
when(modern.type()).thenReturn(SimpleEvent.class);
assertEquals(SimpleEvent.class.getName(), LegacyEventAttribution.source(modern, true));
}

private SkriptEventInfo.ModernSkriptEventInfo<?> legacy(String path) {
var event = mock(SkriptEventInfo.ModernSkriptEventInfo.class);
when(event.type()).thenReturn(SimpleEvent.class);
when(event.getOriginClassPath()).thenReturn(path);
return event;
}
}