commit 2e1762f851b1a5f5946b1801fe3523f257ce16f8 Author: Reece Wilson Date: Fri Mar 3 19:19:06 2023 +0000 Initial Commit diff --git a/gtkts.js b/gtkts.js new file mode 100644 index 0000000..d3d2fd1 --- /dev/null +++ b/gtkts.js @@ -0,0 +1,375 @@ +const kExportAllInOne = false + +let repo = AuGlib.GetGTKRepo() +let buffer = "" + +let namespaceMap = { + "Gtk": "AuGTK", + "GtkSource": "AuGtkSource", + "GLib": "AuGlibEx", + "Gio": "AuGIO", + "Gdk": "AuGDK", + "Pango": "AuPango", + "GdkPixbuf": "AuGDKPixBuf", + "cario": "AuCairo" +} + +function getNamespace(ns) { + return namespaceMap[ns] ?? ns +} + +function sanitize(name) { + if (name == "function") return "_func" + if (name == "new") return "_new" + if (name == "") return "_" + if (name == "constructor") return "_constructor" + return name +} + +function isBlackListed(name) { + return name == "MainContext" || + name == "Cond" || + name == "Scanner" || + name == "TypeValueTable" || + name == "VideoScaler" || + name == "InitiallyUnownedClass" || + name == "VideoFrameFlags" || + name == "VideoBufferFlags" +} + +function isInvalidType(name) { + return name == "AuGlibEx.Mutex" || + name == "HarfBuzz.var_int_t" || + name == "GObject._Value__data__union"|| + name == "GObject._Value__data__union[]" || + name == "GModule.Module" || + name == "HarfBuzz.var_num_t" || + name == "void[]" +} + +function dumpType(namespace, type) { + let tag = type.getTag() + switch (Number(tag)) { + case AuGlib.GITypeTag.GI_TYPE_TAG_VOID : { buffer += "void"; break; } + case AuGlib.GITypeTag.GI_TYPE_TAG_UINT8 : { buffer += "number"; break; } + case AuGlib.GITypeTag.GI_TYPE_TAG_BOOLEAN : { buffer += "boolean"; break; } + case AuGlib.GITypeTag.GI_TYPE_TAG_UINT16 : { buffer += "number"; break; } + case AuGlib.GITypeTag.GI_TYPE_TAG_INT8 : { buffer += "number"; break; } + case AuGlib.GITypeTag.GI_TYPE_TAG_INTERFACE : { + if (type.getInterface().isICallable()) { + dumpFunction(type.getInterface().asICallable()) + break; + } + + buffer += getNamespace(type.getInterface().getNamespace()) + "." + type.getInterface().getName(); + break; + } + case AuGlib.GITypeTag.GI_TYPE_TAG_INT16 : { buffer += "number"; break; } + case AuGlib.GITypeTag.GI_TYPE_TAG_INT32 : { buffer += "number"; break; } + case AuGlib.GITypeTag.GI_TYPE_TAG_UINT32 : { buffer += "number"; break; } + case AuGlib.GITypeTag.GI_TYPE_TAG_DOUBLE : { buffer += "number"; break; } + case AuGlib.GITypeTag.GI_TYPE_TAG_INT64 : { buffer += "number"; break; } + case AuGlib.GITypeTag.GI_TYPE_TAG_UINT64 : { buffer += "number"; break; } + case AuGlib.GITypeTag.GI_TYPE_TAG_FLOAT : { buffer += "number"; break; } + case AuGlib.GITypeTag.GI_TYPE_TAG_GTYPE : { buffer += "number"; break; } + case AuGlib.GITypeTag.GI_TYPE_TAG_UTF8 : { buffer += "string"; break; } + case AuGlib.GITypeTag.GI_TYPE_TAG_FILENAME : { buffer += "string"; break; } + case AuGlib.GITypeTag.GI_TYPE_TAG_ARRAY : + case AuGlib.GITypeTag.GI_TYPE_TAG_GLIST : + case AuGlib.GITypeTag.GI_TYPE_TAG_GSLIST : { dumpType("", type.getParameterType(0)); buffer += "[]"; break; } + case AuGlib.GITypeTag.GI_TYPE_TAG_GHASH : { buffer += "number"; break; } + case AuGlib.GITypeTag.GI_TYPE_TAG_ERROR : { buffer += "AuGlibEx.Error"; break; } + case AuGlib.GITypeTag.GI_TYPE_TAG_UNICHAR : { buffer += "string"; break; } + default: buffer += "unhandled case " + AuGlib.GITypeTag[tag]; + } +} + +function dumpConstants(namespace, constants, preface, tbl) { + constants.forEach((constant) => { + let name = constant.getMemberNameLocalized() + if (tbl) { + if (!tbl[name]) { + return; + } + tbl[name] = 1 + } + buffer += preface ?? "" + "\tlet " + name + " : " + dumpType(namespace, constant.getType()) + buffer += ";\n" + }) +} + +function dumpMethod(method) { + let name = method.getMemberNameLocalized() + + if (name == "new") return + + if (!method.isMethod()) + buffer += "static "; + + buffer += sanitize(name) + buffer += "(" + + for (let i = 0; i < method.getNArgs(); i++) { + if (i != 0) buffer += ", " + + let arg = method.getArg(i); + buffer += sanitize(arg.asBase().getName()) + ": " + dumpType("", arg.getType()) + } + + buffer += "): " + dumpType("", method.getReturnType()) +} + +function dumpFunction(method) { + buffer += "(" + + for (let i = 0; i < method.getNArgs(); i++) { + if (i != 0) buffer += ", " + + let arg = method.getArg(i); + buffer += sanitize(arg.asBase().getName()) + ": " + dumpType("", arg.getType()) + } + + buffer += ") => " + dumpType("", method.getReturnType()) +} + + +function dumpInterfaces(namespace, objs) { + objs.forEach((iface) => { + buffer += "\tclass " + iface.asBase().getName() + " {\n" + + let consts = iface.getConstants() + let known = {} + + if (consts.length) { + consts.forEach((constant) => { + known[constant.getMemberNameLocalized()] = 1 + dumpConstants(namespace, constant, "\t") + }) + + buffer += "\n" + } + + iface.getMethods().forEach((method) => { + if (known[method.getMemberNameLocalized()]){ + return + } + + buffer += "\t\t" + dumpMethod(method) + buffer += ";\n" + }) + + buffer += "\t}\n\n" + }) +} + +function dumpField(namespace, constant, preface) { + var start = buffer.length + buffer += "\t\t" + sanitize(constant.getMemberNameLocalized()) + " : " + + var len = buffer.length + + dumpType(namespace, constant.getType()) + + if (isInvalidType(buffer.substr(len))) { + buffer = buffer.substr(0, start) + } else{ + buffer += ";\n" + } +} + +function dumpObjects(namespace, objs) { + objs.forEach((obj) => { + let name = obj.asBase().getName() + if (isBlackListed(name)) { + buffer += "\tclass " + name + " { /*unsupported*/ }\n\n" + return + } + + buffer += "\tclass " + name + " {\n" + + let consts = obj.getConstants() + + if (consts.length) { + consts.forEach((constant) => { + dumpConstants(namespace, constant, "\t") + }) + + buffer += "\n" + } + + buffer += "\t\tconstructor(initializerList: any);\n\n" + + let fields = obj.getFields() + let known = {} + + if (fields.length) { + fields.forEach((field) => { + known[field.getMemberNameLocalized()] = 1 + dumpField(namespace, field, "\t") + }) + + buffer += "\n" + } + + obj.getMethods().forEach((method) => { + if (known[method.getMemberNameLocalized()]){ + return + } + + buffer += "\t\t" + var len = buffer.length + dumpMethod(method) + if (buffer.length == len) { + buffer = buffer.substr(0, buffer.length - 2) + } else{ + buffer += ";\n" + } + }) + + buffer += "\t}\n\n" + }) +} + +function dumpEnums(namespace, enums) { + enums.forEach((enumVal) => { + let name = enumVal.asBase().getName() + + if (isBlackListed(name)) { + buffer += "\tclass " + name + " { /*unsupported*/ }\n\n" + return + } + + buffer += "\tclass " + name + " {\n" + + buffer += ` // Enumerations hack... +\t\ttoString(radix ? : number | undefined) : string; +\t\ttoFixed(fractionDigits ? : number | undefined) : string; +\t\ttoExponential(fractionDigits ? : number | undefined) : string; +\t\ttoPrecision(precision ? : number | undefined) : string; +\t\tvalueOf() : number; +\t\ttoLocaleString(locales ? : string | string[] | undefined, options ? : Intl.NumberFormatOptions | undefined) : string;\n +\t\tstatic [s:number]: string;\n +` + + let values = enumVal.getValues() + values.forEach((val) => { + buffer += "\t\tstatic readonly \"" + buffer += val.getLocalizedName() + buffer += "\": " + name + buffer += "\n" + }) + + buffer += "\t}\n\n" + }) +} + +function dumpStructs(namespace, objs) { + objs.forEach((obj) => { + let name = obj.asBase().getName() + + if (isBlackListed(name)) { + buffer += "\tclass " + name + " { /*unsupported*/ }\n\n" + return + } + + buffer += "\tclass " + name + " {\n" + + let fields = obj.getFields() + let known = {} + + if (fields.length) { + + fields.forEach((field) => { + known[field.getMemberNameLocalized()] = 1 + if (field.getMemberNameLocalized() == "data" && name == "Value") return; + dumpField(namespace, field, "\t") + }) + + buffer += "\n" + } + + obj.getMethods().forEach((method) => { + if (known[method.getMemberNameLocalized()]){ + return + } + + buffer += "\t\t" + dumpMethod(method) + buffer += ";\n" + }) + + buffer += "\t}\n\n" + }) +} + +function printOptNewline() { + if (buffer[buffer.length - 1] != '\n') buffer += "\n" +} + +function dumpNamespace(namespace) { + let infos = repo.getInfos(namespace); + + let enums = infos.filter((info) => { return info.isEnum() }).map((info) => info.asEnumInfo()) + let structs = infos.filter((info) => { return info.isStruct() }).map((info) => info.asStructInfo()) + let objects = infos.filter((info) => { return info.isObject() }).map((info) => info.asObjectInfo()) + let interfaces = infos.filter((info) => { return info.isInterface() }).map((info) => info.asInterfaceInfo()) + let constants = infos.filter((info) => { return info.isConstant() }).map((info) => info.asConstantInfo()) + + + buffer += "declare namespace " + (namespaceMap[namespace] ?? namespace) + " {\n" + + let constRef = {} + dumpConstants(namespace, constants, undefined, constRef) + + printOptNewline() + + dumpEnums(namespace, enums) + + printOptNewline() + + dumpInterfaces(namespace, interfaces) + + printOptNewline() + + dumpStructs(namespace, structs) + + printOptNewline() + + dumpObjects(namespace, objects) + + buffer = buffer.substr(0, buffer.length - 1) + buffer += "}" + + if (!kExportAllInOne) { + AuFS.WriteString(`./Export/${namespace}.d.ts`, buffer) + buffer = "" + } +} + +dumpNamespace("Gtk") +dumpNamespace("Gdk") +dumpNamespace("Gsk") +dumpNamespace("GLib") +dumpNamespace("Gio") +dumpNamespace("GtkSource") +dumpNamespace("GstPlay") +dumpNamespace("GstPlayer") +dumpNamespace("Pango") +dumpNamespace("GObject") +dumpNamespace("GdkPixbuf") +dumpNamespace("cairo") +dumpNamespace("Graphene") +dumpNamespace("Gst") +dumpNamespace("GstVideo") +dumpNamespace("HarfBuzz") +dumpNamespace("GstBase") + +if (kExportAllInOne) { + AuFS.WriteString(`./Export/AllInOne.d.ts`, buffer) +} \ No newline at end of file