2
2
3
3
import com .mojang .datafixers .util .Pair ;
4
4
import com .prunoideae .probejs .toucher .ClassInfo ;
5
+ import dev .latvian .mods .kubejs .recipe .RecipeEventJS ;
5
6
6
7
import java .lang .reflect .*;
7
8
import java .util .*;
@@ -15,6 +16,10 @@ public class TSGlobalClassFormatter {
15
16
public static HashMap <Class <?>, Function <Object , String >> staticValueTransformer = new HashMap <>();
16
17
public static HashMap <String , String > resolvedClassName = new HashMap <>();
17
18
19
+ private static String getCamelCase (String text ) {
20
+ return Character .toLowerCase (text .charAt (0 )) + text .substring (1 );
21
+ }
22
+
18
23
private static Pair <Class <?>, Integer > getClassOrComponent (Class <?> clazz ) {
19
24
if (clazz == null )
20
25
return null ;
@@ -72,6 +77,11 @@ public String format() {
72
77
String resolvedType = specialTypeFormatter .containsKey (clazz )
73
78
? specialTypeFormatter .get (clazz ).apply (this .typeInfo )
74
79
: 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
+ }
75
85
if (arrayDepth != -1 )
76
86
resolvedType += "[]" .repeat (arrayDepth );
77
87
return resolvedType ;
@@ -136,6 +146,8 @@ public String format() {
136
146
String formatted = "%s: %s;" .formatted (this .fieldInfo .getName (), resolvedAnnotation );
137
147
if (this .fieldInfo .isStatic ())
138
148
formatted = "static " + formatted ;
149
+ if (this .fieldInfo .isFinal ())
150
+ formatted = "readonly " + formatted ;
139
151
return formatted ;
140
152
}
141
153
}
@@ -205,9 +217,106 @@ public ClassFormatter setNameGuard(Predicate<String> predicate) {
205
217
protected List <String > compileMethods () {
206
218
int linesIdent = this .indentation + stepIndentation ;
207
219
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
+
208
316
classInfo .getMethods ()
209
317
.stream ()
210
318
.filter (methodInfo -> this .namePredicate .test (methodInfo .getName ()))
319
+ .filter (methodInfo -> !beaned .contains (methodInfo ))
211
320
.forEach (methodInfo -> innerLines .add (" " .repeat (linesIdent ) + new MethodFormatter (methodInfo ).format ()));
212
321
return innerLines ;
213
322
}
0 commit comments