Parsed generic type parameters in .d.ts files. i.e. IPlayer<T extends EntityPlayerMP>

This commit is contained in:
bigguy345 committed 2026-01-08 01:26:01 +02:00
1 parent 8fb683ff2c
commit 798e238804
2 files changed
+124 -8

No files matched your search

@@ -8,10 +8,41 @@ import java.util.*;
*/
public class JSTypeInfo {
/**
* Represents a generic type parameter like "T extends Entity".
* Stores the parameter name, the bound type, and optionally the full Java class name.
*/
public static class TypeParamInfo {
private final String name; // e.g., "T"
private final String boundType; // e.g., "EntityPlayerMP"
private final String fullBoundType; // e.g., "net.minecraft.entity.player.EntityPlayerMP"
public TypeParamInfo(String name, String boundType, String fullBoundType) {
this.name = name;
this.boundType = boundType;
this.fullBoundType = fullBoundType;
}
public String getName() { return name; }
public String getBoundType() { return boundType; }
public String getFullBoundType() { return fullBoundType; }
@Override
public String toString() {
if (boundType != null) {
return name + " extends " + boundType + (fullBoundType != null ? " (" + fullBoundType + ")" : "");
}
return name;
}
}
private final String simpleName; // e.g., "InteractEvent"
private final String fullName; // e.g., "IPlayerEvent.InteractEvent"
private final String namespace; // e.g., "IPlayerEvent" (parent namespace, null for top-level)
// Type parameters (generics)
private final List<TypeParamInfo> typeParams = new ArrayList<>();
// Members
private final Map<String, JSMethodInfo> methods = new LinkedHashMap<>();
private final Map<String, JSFieldInfo> fields = new LinkedHashMap<>();
@@ -72,6 +103,10 @@ public class JSTypeInfo {
this.resolvedParent = parent;
}
public void addTypeParam(TypeParamInfo param) {
typeParams.add(param);
}
// Getters
public String getSimpleName() { return simpleName; }
public String getFullName() { return fullName; }
@@ -80,11 +115,38 @@ public class JSTypeInfo {
public JSTypeInfo getResolvedParent() { return resolvedParent; }
public String getDocumentation() { return documentation; }
public JSTypeInfo getParentType() { return parentType; }
public List<TypeParamInfo> getTypeParams() { return typeParams; }
public Map<String, JSMethodInfo> getMethods() { return methods; }
public Map<String, JSFieldInfo> getFields() { return fields; }
public Map<String, JSTypeInfo> getInnerTypes() { return innerTypes; }
/**
* Get the type parameter info for a given parameter name (e.g., "T").
* @return TypeParamInfo or null if not found
*/
public TypeParamInfo getTypeParam(String name) {
for (TypeParamInfo param : typeParams) {
if (param.getName().equals(name)) {
return param;
}
}
return null;
}
/**
* Resolves a type parameter to its bound type.
* For example, if this type has "T extends EntityPlayerMP", resolveTypeParam("T") returns "EntityPlayerMP".
* If no type parameter is found with that name, returns the input.
*/
public String resolveTypeParam(String typeName) {
TypeParamInfo param = getTypeParam(typeName);
if (param != null && param.getBoundType() != null) {
return param.getBoundType();
}
return typeName;
}
/**
* Get a method by name, including inherited methods.
*/
@@ -12,17 +12,21 @@ import java.util.zip.*;
public class TypeScriptDefinitionParser {
// Patterns for parsing .d.ts content
// Updated to handle generic type parameters like: export interface IEntityLivingBase<T> extends IEntity {
// Updated to capture generic type parameters like: export interface IEntity<T extends Entity /* net.minecraft.entity.Entity */>
private static final Pattern INTERFACE_PATTERN = Pattern.compile(
"export\\s+interface\\s+(\\w+)(?:<[^>]*>)?(?:\\s+extends\\s+([^{]+?))?\\s*\\{");
"export\\s+interface\\s+(\\w+)(?:<([^>]*)>)?(?:\\s+extends\\s+([^{]+?))?\\s*\\{");
// Pattern for nested interfaces without export keyword
private static final Pattern NESTED_INTERFACE_PATTERN = Pattern.compile(
"(?<!export\\s)\\binterface\\s+(\\w+)(?:<[^>]*>)?(?:\\s+extends\\s+([^{]+?))?\\s*\\{");
"(?<!export\\s)\\binterface\\s+(\\w+)(?:<([^>]*)>)?(?:\\s+extends\\s+([^{]+?))?\\s*\\{");
// Similar pattern for classes
private static final Pattern CLASS_PATTERN = Pattern.compile(
"export\\s+class\\s+(\\w+)(?:<[^>]*>)?(?:\\s+extends\\s+([^{]+?))?\\s*\\{");
"export\\s+class\\s+(\\w+)(?:<([^>]*)>)?(?:\\s+extends\\s+([^{]+?))?\\s*\\{");
// Pattern to parse individual type parameters like: T extends EntityPlayerMP /* net.minecraft.entity.player.EntityPlayerMP */
private static final Pattern TYPE_PARAM_PATTERN = Pattern.compile(
"(\\w+)(?:\\s+extends\\s+(\\w+)(?:\\s*/\\*\\s*([\\w.]+)\\s*\\*/)?)?");
// Match both "export namespace" and plain "namespace" (for declare global blocks)
private static final Pattern NAMESPACE_PATTERN = Pattern.compile(
@@ -166,9 +170,16 @@ public class TypeScriptDefinitionParser {
Matcher interfaceMatcher = INTERFACE_PATTERN.matcher(content);
while (interfaceMatcher.find()) {
String interfaceName = interfaceMatcher.group(1);
String extendsClause = interfaceMatcher.group(2);
String typeParamsStr = interfaceMatcher.group(2); // e.g., "T extends EntityPlayerMP /* net.minecraft.entity.player.EntityPlayerMP */"
String extendsClause = interfaceMatcher.group(3);
JSTypeInfo typeInfo = new JSTypeInfo(interfaceName, parentNamespace);
// Parse type parameters
if (typeParamsStr != null && !typeParamsStr.isEmpty()) {
parseTypeParameters(typeParamsStr, typeInfo);
}
if (extendsClause != null) {
// Handle multiple extends (e.g., "IEntityLivingBase<T>, IAnimatable")
// Take the first one, stripping generics
@@ -204,9 +215,16 @@ public class TypeScriptDefinitionParser {
Matcher nestedInterfaceMatcher = NESTED_INTERFACE_PATTERN.matcher(content);
while (nestedInterfaceMatcher.find()) {
String interfaceName = nestedInterfaceMatcher.group(1);
String extendsClause = nestedInterfaceMatcher.group(2);
String typeParamsStr = nestedInterfaceMatcher.group(2);
String extendsClause = nestedInterfaceMatcher.group(3);
JSTypeInfo typeInfo = new JSTypeInfo(interfaceName, parentNamespace);
// Parse type parameters
if (typeParamsStr != null && !typeParamsStr.isEmpty()) {
parseTypeParameters(typeParamsStr, typeInfo);
}
if (extendsClause != null) {
String extendsType = extendsClause.trim();
extendsType = extendsType.replaceAll("<[^>]*>", "");
@@ -232,9 +250,16 @@ public class TypeScriptDefinitionParser {
Matcher classMatcher = CLASS_PATTERN.matcher(content);
while (classMatcher.find()) {
String className = classMatcher.group(1);
String extendsClause = classMatcher.group(2);
String typeParamsStr = classMatcher.group(2);
String extendsClause = classMatcher.group(3);
JSTypeInfo typeInfo = new JSTypeInfo(className, parentNamespace);
// Parse type parameters
if (typeParamsStr != null && !typeParamsStr.isEmpty()) {
parseTypeParameters(typeParamsStr, typeInfo);
}
if (extendsClause != null) {
String extendsType = extendsClause.trim();
extendsType = extendsType.replaceAll("<[^>]*>", "");
@@ -283,6 +308,28 @@ public class TypeScriptDefinitionParser {
}
}
/**
* Parse type parameters from a string like "T extends EntityPlayerMP /* net.minecraft.entity.player.EntityPlayerMP *`/".
* Handles multiple parameters separated by commas.
*/
private void parseTypeParameters(String typeParamsStr, JSTypeInfo typeInfo) {
// Split by comma, but be careful with nested generics (shouldn't happen at this level, but be safe)
String[] params = typeParamsStr.split(",");
for (String param : params) {
param = param.trim();
if (param.isEmpty()) continue;
Matcher m = TYPE_PARAM_PATTERN.matcher(param);
if (m.find()) {
String name = m.group(1);
String boundType = m.group(2);
String fullBoundType = m.group(3);
typeInfo.addTypeParam(new JSTypeInfo.TypeParamInfo(name, boundType, fullBoundType));
}
}
}
/**
* Parse nested types (interfaces and type aliases) within a parent type or namespace.
*/
@@ -291,9 +338,16 @@ public class TypeScriptDefinitionParser {
Matcher nestedInterfaceMatcher = NESTED_INTERFACE_PATTERN.matcher(content);
while (nestedInterfaceMatcher.find()) {
String interfaceName = nestedInterfaceMatcher.group(1);
String extendsClause = nestedInterfaceMatcher.group(2);
String typeParamsStr = nestedInterfaceMatcher.group(2);
String extendsClause = nestedInterfaceMatcher.group(3);
JSTypeInfo typeInfo = new JSTypeInfo(interfaceName, namespace);
// Parse type parameters
if (typeParamsStr != null && !typeParamsStr.isEmpty()) {
parseTypeParameters(typeParamsStr, typeInfo);
}
if (extendsClause != null) {
String extendsType = extendsClause.trim();
extendsType = extendsType.replaceAll("<[^>]*>", "");