From 869dda34a5f7f55fbf7fc2c96995b9c1e8deb4cc Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Thu, 8 Jan 2026 04:09:18 +0200 Subject: [PATCH] -Java class types can are now functional in JS API. (Autocomplete and marking) -Revamped JSMethodInfo/ParamInfo/FieldInfo/TypeInfo to allow for the above change --- .../interpreter/js_parser/JSFieldInfo.java | 54 ++++++++++- .../interpreter/js_parser/JSMethodInfo.java | 96 ++++++++++++++++++- .../interpreter/js_parser/JSTypeInfo.java | 30 ++++++ .../interpreter/js_parser/JSTypeRegistry.java | 15 +++ .../script/interpreter/method/MethodInfo.java | 27 +----- .../script/interpreter/type/TypeResolver.java | 14 ++- 6 files changed, 210 insertions(+), 26 deletions(-) diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/js_parser/JSFieldInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/js_parser/JSFieldInfo.java index 4ff653071..fc1ccd642 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/js_parser/JSFieldInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/js_parser/JSFieldInfo.java @@ -1,14 +1,18 @@ package noppes.npcs.client.gui.util.script.interpreter.js_parser; +import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo; +import noppes.npcs.client.gui.util.script.interpreter.type.TypeResolver; /** * Represents a field/property in a TypeScript interface. */ public class JSFieldInfo { private final String name; - private final String type; // Raw type string + private final String type; // Raw type string for display + private TypeInfo typeInfo; // Resolved TypeInfo private final boolean readonly; private String documentation; + private JSTypeInfo containingType; // The type that contains this field public JSFieldInfo(String name, String type, boolean readonly) { this.name = name; @@ -21,11 +25,59 @@ public class JSFieldInfo { return this; } + + /** + * Set the containing type (the JSTypeInfo that owns this field). + */ + public void setContainingType(JSTypeInfo containingType) { + this.containingType = containingType; + } + + public void setTypeInfo(TypeInfo typeInfo) { + this.typeInfo = typeInfo; + } + + /** + * Get the resolved type, with fallback resolution using type parameters. + * @param contextType The TypeInfo context for resolving type parameters + * @return The resolved TypeInfo for the field type + */ + public TypeInfo getResolvedType(TypeInfo contextType) { + // Use pre-resolved if available + if (typeInfo != null && typeInfo.isResolved()) + return typeInfo; + + // Fall back to resolving from string + TypeResolver resolver = TypeResolver.getInstance(); + TypeInfo resolved = typeInfo = resolver.resolveJSType(type); + + // If not resolved and contextType has type parameters, try to resolve as type parameter + if (contextType != null && !resolved.isResolved()) { + TypeInfo paramResolution = contextType.resolveTypeParamToTypeInfo(type); + if (paramResolution != null) + resolved = typeInfo = paramResolution; // cache it to typeInfo + } + + return resolved; + } + // Getters public String getName() { return name; } public String getType() { return type; } + public TypeInfo getTypeInfo() { return typeInfo; } public boolean isReadonly() { return readonly; } public String getDocumentation() { return documentation; } + public JSTypeInfo getContainingType() { return containingType; } + + /** + * Get display name - uses resolved TypeInfo simple name if available. + */ + public String getDisplayType() { + if (typeInfo != null && typeInfo.isResolved()) { + return typeInfo.getSimpleName(); + } + return type; + } /** * Build hover info HTML for this field. diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/js_parser/JSMethodInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/js_parser/JSMethodInfo.java index 2d5c03d1d..8999582de 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/js_parser/JSMethodInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/js_parser/JSMethodInfo.java @@ -1,5 +1,8 @@ package noppes.npcs.client.gui.util.script.interpreter.js_parser; +import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo; +import noppes.npcs.client.gui.util.script.interpreter.type.TypeResolver; + import java.util.*; /** @@ -8,9 +11,11 @@ import java.util.*; public class JSMethodInfo { private final String name; - private final String returnType; // Raw type string, e.g., "number", "IEntity", "void" + private final String returnType; // Raw type string for display, e.g., "number", "IEntity", "void" + private TypeInfo returnTypeInfo; // Resolved TypeInfo (set during Phase 2) private final List parameters; private String documentation; + private JSTypeInfo containingType; // The type that contains this method public JSMethodInfo(String name, String returnType, List parameters) { this.name = name; @@ -22,13 +27,56 @@ public class JSMethodInfo { this.documentation = documentation; return this; } + + /** + * Set the resolved return type info (called during Phase 2 type resolution). + */ + public void setReturnTypeInfo(TypeInfo typeInfo) { + this.returnTypeInfo = typeInfo; + } + + /** + * Set the containing type (the JSTypeInfo that owns this method). + */ + public void setContainingType(JSTypeInfo containingType) { + this.containingType = containingType; + // Also set for all parameters + for (JSParameterInfo param : parameters) + param.setContainingMethod(this); + } + + /** + * Get the resolved return type, with fallback resolution using type parameters. + * @param contextType The TypeInfo context for resolving type parameters (e.g., IPlayer to resolve T → EntityPlayerMP) + * @return The resolved TypeInfo for the return type + */ + public TypeInfo getResolvedReturnType(TypeInfo contextType) { + // Use pre-resolved if available + if (returnTypeInfo != null && returnTypeInfo.isResolved()) + return returnTypeInfo; + + // Fall back to resolving from string + TypeResolver resolver = TypeResolver.getInstance(); + TypeInfo resolved = returnTypeInfo = resolver.resolveJSType(returnType); + + // If not resolved and contextType has type parameters, try to resolve as type parameter + if (contextType != null && !resolved.isResolved()) { + TypeInfo paramResolution = contextType.resolveTypeParamToTypeInfo(returnType); + if (paramResolution != null) + resolved = returnTypeInfo = paramResolution; //cache it to returnTypeInfo + } + + return resolved; + } // Getters public String getName() { return name; } public String getReturnType() { return returnType; } + public TypeInfo getReturnTypeInfo() { return returnTypeInfo; } public List getParameters() { return parameters; } public String getDocumentation() { return documentation; } public int getParameterCount() { return parameters.size(); } + public JSTypeInfo getContainingType() { return containingType; } /** * Get a formatted signature string for display. @@ -76,14 +124,60 @@ public class JSMethodInfo { public static class JSParameterInfo { private final String name; private final String type; + private TypeInfo typeInfo; // Resolved TypeInfo (set during Phase 2) + private JSMethodInfo containingMethod; // The type that contains the method with this parameter public JSParameterInfo(String name, String type) { this.name = name; this.type = type; } + + public void setContainingMethod(JSMethodInfo containingMethod) { + this.containingMethod = containingMethod; + } + + public void setTypeInfo(TypeInfo typeInfo) { + this.typeInfo = typeInfo; + } + + /** + * Get the resolved type, with fallback resolution using type parameters. + * @param contextType The TypeInfo context for resolving type parameters + * @return The resolved TypeInfo for the parameter type + */ + public TypeInfo getResolvedType(TypeInfo contextType) { + // Use pre-resolved if available + if (typeInfo != null && typeInfo.isResolved()) + return typeInfo; + + // Fall back to resolving from string + TypeResolver resolver = TypeResolver.getInstance(); + TypeInfo resolved = typeInfo = resolver.resolveJSType(type); + + // If not resolved and contextType has type parameters, try to resolve as type parameter + if (contextType != null && !resolved.isResolved()) { + TypeInfo paramResolution = contextType.resolveTypeParamToTypeInfo(type); + if (paramResolution != null) + resolved = typeInfo = paramResolution; //cache it to typeInfo + } + + return resolved; + } public String getName() { return name; } public String getType() { return type; } + public TypeInfo getTypeInfo() {return typeInfo;} + public JSMethodInfo getContainingMethod() {return containingMethod;} + + /** + * Get display name - uses resolved TypeInfo simple name if available. + */ + public String getDisplayType() { + if (typeInfo != null && typeInfo.isResolved()) { + return typeInfo.getSimpleName(); + } + return type; + } @Override public String toString() { 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 c7c06e715..f25e63a6b 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 @@ -1,6 +1,7 @@ package noppes.npcs.client.gui.util.script.interpreter.js_parser; import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo; +import noppes.npcs.client.gui.util.script.interpreter.type.TypeResolver; import java.util.*; @@ -50,6 +51,7 @@ public class JSTypeInfo { } public void addMethod(JSMethodInfo method) { + method.setContainingType(this); // Handle overloads - store with index if name already exists String key = method.getName(); if (methods.containsKey(key)) { @@ -65,6 +67,7 @@ public class JSTypeInfo { } public void addField(JSFieldInfo field) { + field.setContainingType(this); fields.put(field.getName(), field); } @@ -118,6 +121,33 @@ public class JSTypeInfo { } } + /** + * Resolve all member types (return types, field types, parameter types). + * Called during Phase 2 after all types are loaded into the registry. + * This resolves types like "Java.java.io.File" to proper TypeInfo objects. + */ + public void resolveMemberTypes() { + TypeResolver resolver = TypeResolver.getInstance(); + + // Resolve method return types and parameter types + for (JSMethodInfo method : methods.values()) { + TypeInfo returnTypeInfo = resolver.resolveJSType(method.getReturnType()); + method.setReturnTypeInfo(returnTypeInfo); + + // Resolve parameter types + for (JSMethodInfo.JSParameterInfo param : method.getParameters()) { + TypeInfo paramTypeInfo = resolver.resolveJSType(param.getType()); + param.setTypeInfo(paramTypeInfo); + } + } + + // Resolve field types + for (JSFieldInfo field : fields.values()) { + TypeInfo fieldTypeInfo = resolver.resolveJSType(field.getType()); + field.setTypeInfo(fieldTypeInfo); + } + } + /** * Resolves a type parameter to its bound TypeInfo. * For example, if this type has "T extends EntityPlayerMP", resolveTypeParam("T") returns the TypeInfo for EntityPlayerMP. diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/js_parser/JSTypeRegistry.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/js_parser/JSTypeRegistry.java index a4565b5eb..5d4dfe15c 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/js_parser/JSTypeRegistry.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/js_parser/JSTypeRegistry.java @@ -86,6 +86,9 @@ public class JSTypeRegistry { // Phase 2: Resolve all type parameters now that all types are loaded resolveAllTypeParameters(); + // Phase 2b: Resolve member types (return types, field types, param types) + resolveAllMemberTypes(); + resolveInheritance(); registerEngineGlobalObjects(); @@ -227,6 +230,7 @@ public class JSTypeRegistry { TypeScriptDefinitionParser parser = new TypeScriptDefinitionParser(this); parser.parseDirectory(directory); resolveAllTypeParameters(); + resolveAllMemberTypes(); resolveInheritance(); initialized = true; System.out.println("[JSTypeRegistry] Loaded " + types.size() + " types, " + hooks.size() + " hooks"); @@ -246,6 +250,7 @@ public class JSTypeRegistry { TypeScriptDefinitionParser parser = new TypeScriptDefinitionParser(this); parser.parseVsixArchive(vsixFile); resolveAllTypeParameters(); + resolveAllMemberTypes(); resolveInheritance(); initialized = true; System.out.println("[JSTypeRegistry] Loaded " + types.size() + " types, " + hooks.size() + " hooks from VSIX"); @@ -376,6 +381,16 @@ public class JSTypeRegistry { } } + /** + * Resolve all member types (return types, field types, parameter types) for all types. + * Called after resolveAllTypeParameters (Phase 2b). + * This resolves types like "Java.java.io.File" to proper TypeInfo objects. + */ + public void resolveAllMemberTypes() { + for (JSTypeInfo type : types.values()) + type.resolveMemberTypes(); + } + /** * Resolve inheritance relationships between types. * For each type, walks up the parent chain and resolves all ancestors. diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/method/MethodInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/method/MethodInfo.java index 33c4b7ea5..039127ea5 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/method/MethodInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/method/MethodInfo.java @@ -175,19 +175,9 @@ public final class MethodInfo { */ public static MethodInfo fromJSMethod(JSMethodInfo jsMethod, TypeInfo containingType) { String name = jsMethod.getName(); - noppes.npcs.client.gui.util.script.interpreter.type.TypeResolver resolver = noppes.npcs.client.gui.util.script.interpreter.type.TypeResolver.getInstance(); - // Resolve the return type - first from TypeResolver, then check for type parameters - String returnTypeName = jsMethod.getReturnType(); - TypeInfo returnType = resolver.resolveJSType(returnTypeName); - - // If not resolved and containingType has type parameters, try to resolve as type parameter - if (containingType != null && !returnType.isResolved()) { - TypeInfo paramResolution = containingType.resolveTypeParamToTypeInfo(returnTypeName); - if (paramResolution != null) { - returnType = paramResolution; - } - } + // Use the new getResolvedReturnType method + TypeInfo returnType = jsMethod.getResolvedReturnType(containingType); // Convert JS parameters to FieldInfo List params = new ArrayList<>(); @@ -195,18 +185,9 @@ public final class MethodInfo { for (JSMethodInfo.JSParameterInfo param : jsParams) { String paramName = param.getName(); - String paramTypeName = param.getType(); - // Resolve parameter type - first from TypeResolver, then check for type parameters - TypeInfo paramType = resolver.resolveJSType(paramTypeName); - - // If not resolved and containingType has type parameters, try to resolve as type parameter - if (containingType != null && !paramType.isResolved()) { - TypeInfo paramResolution = containingType.resolveTypeParamToTypeInfo(paramTypeName); - if (paramResolution != null) { - paramType = paramResolution; - } - } + // Use the new getResolvedType method + TypeInfo paramType = param.getResolvedType(containingType); params.add(FieldInfo.reflectionParam(paramName, paramType)); } diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeResolver.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeResolver.java index 228c26040..81349ef52 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeResolver.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeResolver.java @@ -129,7 +129,7 @@ public class TypeResolver { * Resolve a type name for JavaScript context. * Handles JS primitives, .d.ts types, and falls back to Java types. * - * @param jsTypeName The JS type name (e.g., "IPlayer", "string", "number") + * @param jsTypeName The JS type name (e.g., "IPlayer", "string", "number", "Java.java.io.File") * @return TypeInfo for the resolved type, or unresolved TypeInfo if not found */ public TypeInfo resolveJSType(String jsTypeName) { @@ -148,6 +148,18 @@ public class TypeResolver { // Strip array brackets for base type resolution boolean isArray = jsTypeName.endsWith("[]"); String baseName = isArray ? jsTypeName.substring(0, jsTypeName.length() - 2) : jsTypeName; + + // Handle "Java." prefix - convert to actual Java type + // e.g., "Java.java.io.File" -> "java.io.File" + if (baseName.startsWith("Java.")) { + String javaFullName = baseName.substring(5); // Remove "Java." + TypeInfo javaType = resolveFullName(javaFullName); + if (javaType != null && javaType.isResolved()) { + return isArray ? TypeInfo.arrayOf(javaType) : javaType; + } + // Still return unresolved with the cleaned-up name + return TypeInfo.unresolved(javaFullName.substring(javaFullName.lastIndexOf('.') + 1), javaFullName); + } switch (baseName.toLowerCase()) { case "string":