Skip to content

Commit 5a70bca

Browse files
committed
Updated to v1.3.0
Added supports for beans. However, this comes with some extra rules since KubeJS is not completely JS.
1 parent d7b9b74 commit 5a70bca

File tree

5 files changed

+143
-2
lines changed

5 files changed

+143
-2
lines changed

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,18 @@ Auto-completion, type-hinting for most of the functions and classes:
3535
3. Reload your IDE if your IDE doesn't know about the changes of typings, you will see the `onEvent` and `captureEvent`
3636
with correct typings now.
3737
4. If you want to remove the mod, don't forget to replace all `captureEvent` back to `onEvent`.
38+
39+
## 4. Beaning
40+
41+
Bean conversions are added now, however, to make generated typing information comfort with VSCode's TS language server
42+
while applying beaning as much as possible, a few rules are added:
43+
44+
1. Beans will not have naming conflicts with methods/fields existed, if a bean has a conflicted name, the bean will not
45+
be compiled to declaration.
46+
2. For beans with only `.getX()` implemented, `readonly` will be automatically added to prevent coincidental writes to
47+
the field. For beans with any `.setX()` implemented, the bean will be able to read/write, regardless of it has
48+
a `.getX()` or not, as `writeonly` does not exist in TypeScript. This applies to `.isX()` beans too.
49+
3. If `.isX()` has a `.setX()` or `.getX()` part with same name, the latter will override `.isX()` to prevent loss of
50+
information.
51+
4. Original getter and setter methods are hidden, but still callable, however, calling them will not have typing support
52+
as these methods are ignored in method dumping.

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ apply from: 'https://files.latmod.com/public/markdown-git-changelog.gradle'
99
sourceCompatibility = targetCompatibility = JavaVersion.VERSION_17
1010

1111
def ENV = System.getenv()
12-
version = "${mod_version}-build.17"
12+
version = "${mod_version}-build.18"
1313
archivesBaseName = project.archives_base_name
1414
group = project.maven_group
1515

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ org.gradle.daemon=false
33
loom.platform=forge
44
mod_id=probejs
55
archives_base_name=probejs
6-
mod_version=1.2.0
6+
mod_version=1.3.0
77
maven_group=com.prunoideae
88
mod_author=Prunoideae
99
minecraft_version=1.18.1

src/main/java/com/prunoideae/probejs/toucher/ClassInfo.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,19 @@ public TypeInfo getReturnTypeInfo() {
9191
return new TypeInfo(this.method.getGenericReturnType(), this.method.getReturnType());
9292
}
9393

94+
@Override
95+
public boolean equals(Object o) {
96+
if (this == o) return true;
97+
if (o == null || getClass() != o.getClass()) return false;
98+
MethodInfo that = (MethodInfo) o;
99+
return method.equals(that.method);
100+
}
101+
102+
@Override
103+
public int hashCode() {
104+
return Objects.hash(method);
105+
}
106+
94107
@Override
95108
public String toString() {
96109
return "MethodInfo[" +
@@ -137,6 +150,10 @@ public boolean isStatic() {
137150
return Modifier.isStatic(this.field.getModifiers());
138151
}
139152

153+
public boolean isFinal() {
154+
return Modifier.isFinal(this.field.getModifiers());
155+
}
156+
140157
public TypeInfo getTypeInfo() {
141158
return new TypeInfo(this.field.getGenericType(), this.field.getType());
142159
}

src/main/java/com/prunoideae/probejs/typings/TSGlobalClassFormatter.java

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.mojang.datafixers.util.Pair;
44
import com.prunoideae.probejs.toucher.ClassInfo;
5+
import dev.latvian.mods.kubejs.recipe.RecipeEventJS;
56

67
import java.lang.reflect.*;
78
import java.util.*;
@@ -15,6 +16,10 @@ public class TSGlobalClassFormatter {
1516
public static HashMap<Class<?>, Function<Object, String>> staticValueTransformer = new HashMap<>();
1617
public static HashMap<String, String> resolvedClassName = new HashMap<>();
1718

19+
private static String getCamelCase(String text) {
20+
return Character.toLowerCase(text.charAt(0)) + text.substring(1);
21+
}
22+
1823
private static Pair<Class<?>, Integer> getClassOrComponent(Class<?> clazz) {
1924
if (clazz == null)
2025
return null;
@@ -72,6 +77,11 @@ public String format() {
7277
String resolvedType = specialTypeFormatter.containsKey(clazz)
7378
? specialTypeFormatter.get(clazz).apply(this.typeInfo)
7479
: serializeType(this.typeInfo.getType());
80+
//Ensure to resolve type since TS does not allow non-parameterized types.
81+
if (this.typeInfo.getType() instanceof Class<?> type) {
82+
if (type.getTypeParameters().length != 0)
83+
resolvedType += "<%s>".formatted(String.join(",", Collections.nCopies(type.getTypeParameters().length, "unknown")));
84+
}
7585
if (arrayDepth != -1)
7686
resolvedType += "[]".repeat(arrayDepth);
7787
return resolvedType;
@@ -136,6 +146,8 @@ public String format() {
136146
String formatted = "%s: %s;".formatted(this.fieldInfo.getName(), resolvedAnnotation);
137147
if (this.fieldInfo.isStatic())
138148
formatted = "static " + formatted;
149+
if (this.fieldInfo.isFinal())
150+
formatted = "readonly " + formatted;
139151
return formatted;
140152
}
141153
}
@@ -205,9 +217,106 @@ public ClassFormatter setNameGuard(Predicate<String> predicate) {
205217
protected List<String> compileMethods() {
206218
int linesIdent = this.indentation + stepIndentation;
207219
List<String> innerLines = new ArrayList<>();
220+
/* TODO: add support for beans
221+
* Criteria: tranfsorm .get?() methods to .? fields.
222+
* If an field of same name exist, ignore it.
223+
* .get() beans will be readonly, having a .set() will remove the readonly statement.
224+
* Only having a .set() will NOT make this write-only as TS does not have such a thing.
225+
* */
226+
227+
Set<ClassInfo.MethodInfo> beaned = new HashSet<>();
228+
Set<String> existedNames = classInfo.getFields().stream().map(ClassInfo.FieldInfo::getName).collect(Collectors.toSet());
229+
existedNames.addAll(classInfo.getMethods().stream().map(ClassInfo.MethodInfo::getName).collect(Collectors.toSet()));
230+
231+
//Add class getters/setters to beaned
232+
classInfo.getMethods()
233+
.stream()
234+
.filter(methodInfo -> !methodInfo.getName().equals("get"))
235+
.filter(methodInfo -> methodInfo.getName().startsWith("get"))
236+
.filter(methodInfo -> !Character.isDigit(methodInfo.getName().substring(3).charAt(0)))
237+
.filter(methodInfo -> !existedNames.contains(getCamelCase(methodInfo.getName().substring(3))))
238+
.filter(methodInfo -> methodInfo.getParamsInfo().size() == 0)
239+
.forEach(beaned::add);
240+
241+
classInfo.getMethods()
242+
.stream()
243+
.filter(methodInfo -> !methodInfo.getName().equals("set"))
244+
.filter(methodInfo -> methodInfo.getName().startsWith("set"))
245+
.filter(methodInfo -> !Character.isDigit(methodInfo.getName().substring(3).charAt(0)))
246+
.filter(methodInfo -> methodInfo.getParamsInfo().size() == 1)
247+
.filter(methodInfo -> !existedNames.contains(getCamelCase(methodInfo.getName().substring(3))))
248+
.forEach(beaned::add);
249+
250+
//Iterate through getter/setters, generate beans.
251+
Set<String> beanedNames = new HashSet<>();
252+
HashMap<String, ClassInfo.MethodInfo> cachedGetterNames = new HashMap<>();
253+
beaned.forEach(methodInfo -> {
254+
//TODO: Make it more convenient, although idk how
255+
if (classInfo.getClazz() == RecipeEventJS.class) {
256+
if (methodInfo.getName().equals("getRecipes"))
257+
return;
258+
}
259+
String beanName = getCamelCase(methodInfo.getName().substring(3));
260+
if (methodInfo.getName().startsWith("get")) {
261+
if (beanedNames.contains(beanName))
262+
return;
263+
cachedGetterNames.put(beanName, methodInfo);
264+
} else if (methodInfo.getName().startsWith("set")) {
265+
beanedNames.add(beanName);
266+
cachedGetterNames.remove(beanName);
267+
Type type = methodInfo.getParamsInfo().get(0).getType();
268+
String resolved = serializeType(type);
269+
if (type instanceof Class<?> clazz) {
270+
if (clazz.getTypeParameters().length != 0)
271+
resolved += "<%s>".formatted(String.join(",", Collections.nCopies(clazz.getTypeParameters().length, "unknown")));
272+
}
273+
String formatted = "%s: %s;".formatted(beanName, resolved);
274+
if (methodInfo.isStatic())
275+
formatted = "static " + formatted;
276+
innerLines.add(" ".repeat(linesIdent) + formatted);
277+
}
278+
});
279+
280+
classInfo.getMethods()
281+
.stream()
282+
.filter(methodInfo -> !methodInfo.getName().equals("is"))
283+
.filter(methodInfo -> methodInfo.getName().startsWith("is"))
284+
.filter(methodInfo -> !Character.isDigit(methodInfo.getName().substring(2).charAt(0)))
285+
.filter(methodInfo -> !existedNames.contains(getCamelCase(methodInfo.getName().substring(2))))
286+
.filter(methodInfo -> methodInfo.getParamsInfo().size() == 0)
287+
.filter(methodInfo -> {
288+
Type type = methodInfo.getReturnTypeInfo().getType();
289+
return type instanceof Class && (type == Boolean.TYPE || type == Boolean.class);
290+
})
291+
.filter(methodInfo -> !beanedNames.contains(getCamelCase(methodInfo.getName().substring(2))))
292+
.forEach(methodInfo -> {
293+
beaned.add(methodInfo);
294+
String formatted = "%s: boolean;".formatted(getCamelCase(methodInfo.getName().substring(2)));
295+
if (methodInfo.isStatic())
296+
formatted = "static " + formatted;
297+
formatted = "readonly " + formatted;
298+
innerLines.add(" ".repeat(linesIdent) + formatted);
299+
});
300+
301+
302+
cachedGetterNames.forEach((k, v) -> {
303+
Type type = v.getReturnTypeInfo().getType();
304+
String resolved = serializeType(v.getReturnTypeInfo().getType());
305+
if (type instanceof Class<?> clazz) {
306+
if (clazz.getTypeParameters().length != 0)
307+
resolved += "<%s>".formatted(String.join(",", Collections.nCopies(clazz.getTypeParameters().length, "any")));
308+
}
309+
String formatted = "%s: %s;".formatted(k, resolved);
310+
if (v.isStatic())
311+
formatted = "static " + formatted;
312+
formatted = "readonly " + formatted;
313+
innerLines.add(" ".repeat(linesIdent) + formatted);
314+
});
315+
208316
classInfo.getMethods()
209317
.stream()
210318
.filter(methodInfo -> this.namePredicate.test(methodInfo.getName()))
319+
.filter(methodInfo -> !beaned.contains(methodInfo))
211320
.forEach(methodInfo -> innerLines.add(" ".repeat(linesIdent) + new MethodFormatter(methodInfo).format()));
212321
return innerLines;
213322
}

0 commit comments

Comments
 (0)