From 798e238804137576cb153c219528a855ba620edd Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Thu, 8 Jan 2026 01:26:01 +0200 Subject: [PATCH] Parsed generic type parameters in .d.ts files. i.e. IPlayer --- .../interpreter/js_parser/JSTypeInfo.java | 62 ++++++++++++++++ .../js_parser/TypeScriptDefinitionParser.java | 70 ++++++++++++++++--- 2 files changed, 124 insertions(+), 8 deletions(-) diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/js_parser/JSTypeInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/js_parser/JSTypeInfo.java index 7efdd8481..5863d0412 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/js_parser/JSTypeInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/js_parser/JSTypeInfo.java @@ -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 typeParams = new ArrayList<>(); + // Members private final Map methods = new LinkedHashMap<>(); private final Map 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 getTypeParams() { return typeParams; } public Map getMethods() { return methods; } public Map getFields() { return fields; } public Map 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. */ diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/js_parser/TypeScriptDefinitionParser.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/js_parser/TypeScriptDefinitionParser.java index b3615cad8..5403f2ce8 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/js_parser/TypeScriptDefinitionParser.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/js_parser/TypeScriptDefinitionParser.java @@ -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 extends IEntity { + // Updated to capture generic type parameters like: export interface IEntity 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( - "(?]*>)?(?:\\s+extends\\s+([^{]+?))?\\s*\\{"); + "(?]*)>)?(?:\\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, 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("<[^>]*>", "");