-Java class types can are now functional in JS API. (Autocomplete and marking)

-Revamped JSMethodInfo/ParamInfo/FieldInfo/TypeInfo to allow for the above change
This commit is contained in:
bigguy345 committed 2026-01-08 04:09:18 +02:00
1 parent 99f7d05948
commit 869dda34a5
6 files changed
+210 -26

No files matched your search

@@ -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.
@@ -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<JSParameterInfo> parameters;
private String documentation;
private JSTypeInfo containingType; // The type that contains this method
public JSMethodInfo(String name, String returnType, List<JSParameterInfo> 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<JSParameterInfo> 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() {
@@ -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.
@@ -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.
@@ -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<FieldInfo> 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));
}
@@ -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":