diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/field/FieldInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/field/FieldInfo.java index ec3958f02..55834d311 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/field/FieldInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/field/FieldInfo.java @@ -182,9 +182,13 @@ public final class FieldInfo { } // Use documentation if available - String documentation = jsField.getDocumentation(); + JSDocInfo jsDocInfo = jsField.getJsDocInfo(); + String jsDocDesc = jsDocInfo != null ? jsDocInfo.getDescription() : null; + String documentation = jsDocDesc != null ? jsDocDesc : jsField.getDocumentation(); - return new FieldInfo(name, Scope.GLOBAL, type, -1, true, null, documentation, -1, -1, modifiers, null); + FieldInfo fieldInfo = new FieldInfo(name, Scope.GLOBAL, type, -1, true, null, documentation, -1, -1, modifiers, null); + fieldInfo.setJSDocInfo(jsDocInfo); + return fieldInfo; } /** diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverInfo.java index 2a1cece89..216a9102d 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverInfo.java @@ -666,6 +666,23 @@ public class TokenHoverInfo { } } + } else if (typeInfo.isJSType()) { + JSTypeInfo jsType = typeInfo.getJSTypeInfo(); + + iconIndicator = "I"; + addSegment("interface ", TokenType.MODIFIER.getHexColor()); + addSegment(getName(typeInfo), TokenType.INTERFACE_DECL.getHexColor()); + + if (jsType.getExtendsType() != null) { + addSegment(" extends ", TokenType.MODIFIER.getHexColor()); + addSegment(jsType.getExtendsType(), TokenType.INTERFACE_DECL.getHexColor()); + } + + JSDocInfo jsDocInfo = typeInfo.getJSDocInfo(); + if (jsDocInfo != null) { + formatJSDocumentation(jsDocInfo, null); + } + } else { // Unresolved type iconIndicator = "?"; 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 fc1ccd642..afcb09a6b 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,5 +1,6 @@ package noppes.npcs.client.gui.util.script.interpreter.js_parser; +import noppes.npcs.client.gui.util.script.interpreter.jsdoc.JSDocInfo; import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo; import noppes.npcs.client.gui.util.script.interpreter.type.TypeResolver; /** @@ -11,7 +12,7 @@ public class JSFieldInfo { private final String type; // Raw type string for display private TypeInfo typeInfo; // Resolved TypeInfo private final boolean readonly; - private String documentation; + private JSDocInfo jsDocInfo; private JSTypeInfo containingType; // The type that contains this field public JSFieldInfo(String name, String type, boolean readonly) { @@ -20,8 +21,8 @@ public class JSFieldInfo { this.readonly = readonly; } - public JSFieldInfo setDocumentation(String documentation) { - this.documentation = documentation; + public JSFieldInfo setJsDocInfo(JSDocInfo jsDocInfo) { + this.jsDocInfo = jsDocInfo; return this; } @@ -66,9 +67,17 @@ public class JSFieldInfo { public String getType() { return type; } public TypeInfo getTypeInfo() { return typeInfo; } public boolean isReadonly() { return readonly; } - public String getDocumentation() { return documentation; } + public JSDocInfo getJsDocInfo() { return jsDocInfo; } public JSTypeInfo getContainingType() { return containingType; } + /** + * Get documentation string (backward compatibility). + * Extracts description from JSDocInfo if available. + */ + public String getDocumentation() { + return jsDocInfo != null ? jsDocInfo.getDescription() : null; + } + /** * Get display name - uses resolved TypeInfo simple name if available. */ @@ -89,8 +98,8 @@ public class JSFieldInfo { } sb.append("").append(name).append(": ").append(type).append(""); - if (documentation != null && !documentation.isEmpty()) { - sb.append("

").append(documentation); + if (jsDocInfo != null && jsDocInfo.getDescription() != null && !jsDocInfo.getDescription().isEmpty()) { + sb.append("

").append(jsDocInfo.getDescription()); } return sb.toString(); 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 8999582de..6aef02b7f 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,6 @@ package noppes.npcs.client.gui.util.script.interpreter.js_parser; +import noppes.npcs.client.gui.util.script.interpreter.jsdoc.JSDocInfo; import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo; import noppes.npcs.client.gui.util.script.interpreter.type.TypeResolver; @@ -14,7 +15,7 @@ public class JSMethodInfo { 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 JSDocInfo jsDocInfo; private JSTypeInfo containingType; // The type that contains this method public JSMethodInfo(String name, String returnType, List parameters) { @@ -23,8 +24,8 @@ public class JSMethodInfo { this.parameters = parameters != null ? new ArrayList<>(parameters) : new ArrayList<>(); } - public JSMethodInfo setDocumentation(String documentation) { - this.documentation = documentation; + public JSMethodInfo setJsDocInfo(JSDocInfo jsDocInfo) { + this.jsDocInfo = jsDocInfo; return this; } @@ -74,10 +75,18 @@ public class JSMethodInfo { public String getReturnType() { return returnType; } public TypeInfo getReturnTypeInfo() { return returnTypeInfo; } public List getParameters() { return parameters; } - public String getDocumentation() { return documentation; } + public JSDocInfo getJsDocInfo() { return jsDocInfo; } public int getParameterCount() { return parameters.size(); } public JSTypeInfo getContainingType() { return containingType; } + /** + * Get documentation string (backward compatibility). + * Extracts description from JSDocInfo if available. + */ + public String getDocumentation() { + return jsDocInfo != null ? jsDocInfo.getDescription() : null; + } + /** * Get a formatted signature string for display. */ @@ -106,8 +115,8 @@ public class JSMethodInfo { } sb.append("): ").append(returnType).append(""); - if (documentation != null && !documentation.isEmpty()) { - sb.append("

").append(documentation); + if (jsDocInfo != null && jsDocInfo.getDescription() != null && !jsDocInfo.getDescription().isEmpty()) { + sb.append("

").append(jsDocInfo.getDescription()); } return sb.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 f25e63a6b..8bdab8493 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,5 +1,9 @@ package noppes.npcs.client.gui.util.script.interpreter.js_parser; +import noppes.npcs.client.gui.util.script.interpreter.jsdoc.JSDocInfo; +import noppes.npcs.client.gui.util.script.interpreter.jsdoc.JSDocParamTag; +import noppes.npcs.client.gui.util.script.interpreter.jsdoc.JSDocReturnTag; +import noppes.npcs.client.gui.util.script.interpreter.jsdoc.JSDocTypeTag; import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo; import noppes.npcs.client.gui.util.script.interpreter.type.TypeResolver; @@ -31,7 +35,7 @@ public class JSTypeInfo { private JSTypeInfo parentType; // The containing type (for inner types) // Documentation - private String documentation; + private JSDocInfo jsDocInfo; public JSTypeInfo(String simpleName, String namespace) { this.simpleName = simpleName; @@ -45,8 +49,8 @@ public class JSTypeInfo { return this; } - public JSTypeInfo setDocumentation(String documentation) { - this.documentation = documentation; + public JSTypeInfo setJsDocInfo(JSDocInfo jsDocInfo) { + this.jsDocInfo = jsDocInfo; return this; } @@ -86,7 +90,7 @@ public class JSTypeInfo { public String getNamespace() { return namespace; } public String getExtendsType() { return extendsType; } public JSTypeInfo getResolvedParent() { return resolvedParent; } - public String getDocumentation() { return documentation; } + public JSDocInfo getJsDocInfo() { return jsDocInfo; } public JSTypeInfo getParentType() { return parentType; } public List getTypeParams() { return typeParams; } @@ -148,6 +152,49 @@ public class JSTypeInfo { } } + public void resolveJSDocTypes() { + TypeResolver resolver = TypeResolver.getInstance(); + + if (jsDocInfo != null) { + resolveJSDocInfoTypes(jsDocInfo, resolver); + } + + for (JSMethodInfo method : methods.values()) { + JSDocInfo methodDoc = method.getJsDocInfo(); + if (methodDoc != null) { + resolveJSDocInfoTypes(methodDoc, resolver); + } + } + + for (JSFieldInfo field : fields.values()) { + JSDocInfo fieldDoc = field.getJsDocInfo(); + if (fieldDoc != null) { + resolveJSDocInfoTypes(fieldDoc, resolver); + } + } + } + + private void resolveJSDocInfoTypes(JSDocInfo jsDoc, TypeResolver resolver) { + JSDocTypeTag typeTag = jsDoc.getTypeTag(); + if (typeTag != null && typeTag.hasType() && typeTag.getTypeInfo() == null) { + TypeInfo resolved = resolver.resolveJSType(typeTag.getTypeName()); + typeTag.setType(typeTag.getTypeName(), resolved, typeTag.getTypeStart(), typeTag.getTypeEnd()); + } + + for (JSDocParamTag paramTag : jsDoc.getParamTags()) { + if (paramTag.hasType() && paramTag.getTypeInfo() == null) { + TypeInfo resolved = resolver.resolveJSType(paramTag.getTypeName()); + paramTag.setType(paramTag.getTypeName(), resolved, paramTag.getTypeStart(), paramTag.getTypeEnd()); + } + } + + JSDocReturnTag returnTag = jsDoc.getReturnTag(); + if (returnTag != null && returnTag.hasType() && returnTag.getTypeInfo() == null) { + TypeInfo resolved = resolver.resolveJSType(returnTag.getTypeName()); + returnTag.setType(returnTag.getTypeName(), resolved, returnTag.getTypeStart(), returnTag.getTypeEnd()); + } + } + /** * 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 680172f99..89624c1d4 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 @@ -97,6 +97,9 @@ public class JSTypeRegistry { // Phase 2b: Resolve member types (return types, field types, param types) resolveAllMemberTypes(); + // Phase 2c: Resolve JSDoc types (@param, @return, @type type references) + resolveAllJSDocTypes(); + resolveInheritance(); registerEngineGlobalObjects(); @@ -239,6 +242,7 @@ public class JSTypeRegistry { parser.parseDirectory(directory); resolveAllTypeParameters(); resolveAllMemberTypes(); + resolveAllJSDocTypes(); resolveInheritance(); initialized = true; System.out.println("[JSTypeRegistry] Loaded " + types.size() + " types, " + hooks.size() + " hooks"); @@ -259,6 +263,7 @@ public class JSTypeRegistry { parser.parseVsixArchive(vsixFile); resolveAllTypeParameters(); resolveAllMemberTypes(); + resolveAllJSDocTypes(); resolveInheritance(); initialized = true; System.out.println("[JSTypeRegistry] Loaded " + types.size() + " types, " + hooks.size() + " hooks from VSIX"); @@ -594,6 +599,11 @@ public class JSTypeRegistry { type.resolveMemberTypes(); } + public void resolveAllJSDocTypes() { + for (JSTypeInfo type : types.values()) + type.resolveJSDocTypes(); + } + /** * 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/js_parser/TypeScriptDefinitionParser.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/js_parser/TypeScriptDefinitionParser.java index 3e0d8b440..32b832ba9 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 @@ -1,5 +1,7 @@ package noppes.npcs.client.gui.util.script.interpreter.js_parser; +import noppes.npcs.client.gui.util.script.interpreter.jsdoc.JSDocInfo; + import java.io.*; import java.util.*; import java.util.regex.*; @@ -216,6 +218,11 @@ public class TypeScriptDefinitionParser { JSTypeInfo typeInfo = new JSTypeInfo(interfaceName, parentNamespace); + JSDocInfo jsDoc = extractJSDocBefore(content, interfaceMatcher.start()); + if (jsDoc != null) { + typeInfo.setJsDocInfo(jsDoc); + } + // Parse type parameters if (typeParamsStr != null && !typeParamsStr.isEmpty()) { parseTypeParameters(typeParamsStr, typeInfo); @@ -261,6 +268,11 @@ public class TypeScriptDefinitionParser { JSTypeInfo typeInfo = new JSTypeInfo(interfaceName, parentNamespace); + JSDocInfo jsDoc = extractJSDocBefore(content, nestedInterfaceMatcher.start()); + if (jsDoc != null) { + typeInfo.setJsDocInfo(jsDoc); + } + // Parse type parameters if (typeParamsStr != null && !typeParamsStr.isEmpty()) { parseTypeParameters(typeParamsStr, typeInfo); @@ -296,6 +308,11 @@ public class TypeScriptDefinitionParser { JSTypeInfo typeInfo = new JSTypeInfo(className, parentNamespace); + JSDocInfo jsDoc = extractJSDocBefore(content, classMatcher.start()); + if (jsDoc != null) { + typeInfo.setJsDocInfo(jsDoc); + } + // Parse type parameters if (typeParamsStr != null && !typeParamsStr.isEmpty()) { parseTypeParameters(typeParamsStr, typeInfo); @@ -445,6 +462,12 @@ public class TypeScriptDefinitionParser { List parameters = parseParameters(params); JSMethodInfo method = new JSMethodInfo(methodName, returnType, parameters); + + JSDocInfo jsDoc = extractJSDocBefore(body, methodMatcher.start()); + if (jsDoc != null) { + method.setJsDocInfo(jsDoc); + } + typeInfo.addMethod(method); } @@ -460,6 +483,12 @@ public class TypeScriptDefinitionParser { String fieldType = cleanType(fieldMatcher.group(3)); JSFieldInfo field = new JSFieldInfo(fieldName, fieldType, readonly); + + JSDocInfo jsDoc = extractJSDocBefore(body, fieldMatcher.start()); + if (jsDoc != null) { + field.setJsDocInfo(jsDoc); + } + typeInfo.addField(field); } } @@ -568,4 +597,12 @@ public class TypeScriptDefinitionParser { } return sb.toString(); } + + private JSDocInfo extractJSDocBefore(String content, int elementStart) { + String jsDocBlock = DTSJSDocParser.extractJSDocBefore(content, elementStart); + if (jsDocBlock != null) { + return DTSJSDocParser.parseJSDocBlock(jsDocBlock); + } + return null; + } } 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 ababd9816..859d3c0e9 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 @@ -205,9 +205,14 @@ public final class MethodInfo { int modifiers = Modifier.PUBLIC; // Use the documentation from the method if available - String documentation = jsMethod.getDocumentation(); - - return new MethodInfo(name, returnType, containingType, params, -1, -1, -1, -1, -1, true, false, modifiers, documentation, null); + JSDocInfo jsDocInfo = jsMethod.getJsDocInfo(); + String jsDocDesc = jsDocInfo != null ? jsDocInfo.getDescription() : null; + String documentation = jsDocDesc != null ? jsDocDesc : jsMethod.getDocumentation(); + + MethodInfo methodInfo = new MethodInfo(name, returnType, containingType, params, -1, -1, -1, -1, -1, true, + false, modifiers, documentation, null); + methodInfo.setJSDocInfo(jsDocInfo); + return methodInfo; } diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java index 14f4c6242..cb0800ebb 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java @@ -6,6 +6,7 @@ import noppes.npcs.client.gui.util.script.interpreter.js_parser.JSFieldInfo; import noppes.npcs.client.gui.util.script.interpreter.js_parser.JSMethodInfo; import noppes.npcs.client.gui.util.script.interpreter.js_parser.JSTypeInfo; import noppes.npcs.client.gui.util.script.interpreter.js_parser.TypeParamInfo; +import noppes.npcs.client.gui.util.script.interpreter.jsdoc.JSDocInfo; import noppes.npcs.client.gui.util.script.interpreter.method.MethodInfo; import noppes.npcs.client.gui.util.script.interpreter.token.TokenType; @@ -227,6 +228,10 @@ public class TypeInfo { return jsTypeInfo; } + public JSDocInfo getJSDocInfo() { + return jsTypeInfo != null ? jsTypeInfo.getJsDocInfo() : null; + } + // Getters public String getSimpleName() { return simpleName; } public String getFullName() { return fullName; }