package io.vertx.serviceproxy.sockjs.generator;
import io.vertx.codegen.format.CamelCase;
import io.vertx.codegen.Helper;
import io.vertx.codegen.MethodInfo;
import io.vertx.codegen.format.SnakeCase;
import io.vertx.codegen.type.*;
import io.vertx.codegen.writer.CodeWriter;
import io.vertx.serviceproxy.generator.model.ProxyModel;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class SockjsServiceProxyTSGenerator extends SockjsServiceProxyJSGenerator {
@Override
public String filename(ProxyModel model) {
ClassTypeInfo type = model.getType();
return "resources/" + type.getModuleName() + "-js/" + Helper.convertCamelCaseToUnderscores(type.getRaw().getSimpleName()) + "-proxy.d.ts";
}
@Override
public String render(ProxyModel model, int index, int size, Map<String, Object> session) {
StringWriter sw = new StringWriter();
CodeWriter writer = new CodeWriter(sw);
String simpleName = model.getIfaceSimpleName();
genLicenses(writer);
writer.println();
for (ApiTypeInfo referencedType : model.getReferencedTypes()) {
if (referencedType.isProxyGen()) {
String refedType = referencedType.getSimpleName();
writer.format("import { %s } from './%s-proxy';", refedType, getModuleName(referencedType)).println();
}
}
writer.println();
genDoc(model, writer);
writer.format("export default class %s {", simpleName).println();
writer.println();
writer.indent();
writer.println("constructor (eb: any, address: string);");
for (String methodName : model.getMethodMap().keySet()) {
genMethod(model, methodName, false, this::methodFilter, writer);
}
writer.unindent();
writer.print("}");
return sw.toString();
}
private void genMethod(ProxyModel model, String methodName, boolean genStatic, Predicate<MethodInfo> methodFilter, CodeWriter writer) {
String simpleName = model.getIfaceSimpleName();
Map<String, List<MethodInfo>> methodsByName = model.getMethodMap();
List<MethodInfo> methodList = methodsByName.get(methodName);
if (methodFilter != null) {
List<MethodInfo> methodTmpl = methodList;
methodList = new ArrayList<>();
for (MethodInfo method : methodTmpl) {
if (methodFilter.test(method)) {
methodList.add(method);
}
}
}
if (methodList.size() > 0) {
MethodInfo method = methodList.get(methodList.size() - 1);
if (genStatic == method.isStaticMethod()) {
writer.println();
if (genStatic) {
writer.print("static ");
}
writer.format("%s(%s) : ", methodName, method.getParams().stream().map(p -> p.getName() + ": " + getTSDocType(p.getType())).collect(Collectors.joining(", ")));
if (method.isFluent()) {
writer.print(simpleName);
} else {
writer.print("void");
}
writer.println(";");
}
}
}
private String getTSDocType(TypeInfo type) {
if (type.isDataObjectHolder()) {
return "any" + (type.isNullable() ? " | null" : "");
} else {
switch (type.getKind()) {
case STRING:
return "string" + (type.isNullable() ? " | null" : "");
case PRIMITIVE:
case BOXED_PRIMITIVE:
switch (type.getSimpleName()) {
case "boolean":
case "Boolean":
return "boolean" + (type.isNullable() ? " | null" : "");
case "char":
case "Character":
return "string" + (type.isNullable() ? " | null" : "");
default:
return "number" + (type.isNullable() ? " | null" : "");
}
case JSON_OBJECT:
return "Object" + (type.isNullable() ? " | null" : "");
case JSON_ARRAY:
return "Array" + (type.isNullable() ? " | null" : "");
case ENUM:
return "string" + (type.isNullable() ? " | null" : "");
case API:
return type.getRaw().getSimpleName() + (type.isNullable() ? " | null" : "");
case MAP:
return "Object<string, " + getTSDocType(((ParameterizedTypeInfo) type).getArg(1)) + ">" + (type.isNullable() ? " | null" : "");
case SET:
case LIST:
return "Array<" + getTSDocType(((ParameterizedTypeInfo) type).getArg(0)) + ">" + (type.isNullable() ? " | null" : "");
case OBJECT:
return "any";
case HANDLER:
ParameterizedTypeInfo handlerType = (ParameterizedTypeInfo) type;
ParameterizedTypeInfo asyncResultType = (ParameterizedTypeInfo) handlerType.getArg(0);
TypeInfo resultType = asyncResultType.getArg(0);
if (resultType.isDataObjectHolder()) {
return "(err: any, result: " + getTSDocType(resultType) + ") => any";
} else {
switch (resultType.getKind()) {
case API:
case STRING:
case PRIMITIVE:
case JSON_OBJECT:
case JSON_ARRAY:
case ENUM:
case MAP:
case SET:
case LIST:
case OBJECT:
return "(err: any, result: " + getTSDocType(resultType) + ") => any";
default:
return "(err: any, result: any) => any";
}
}
default:
return "todo";
}
}
}
private String getModuleName(ClassTypeInfo type) {
return type.getModuleName() + "-js/" + CamelCase.INSTANCE.to(SnakeCase.INSTANCE, type.getSimpleName());
}
}