GTK-Decl-Dumper/gtkts.js

649 lines
21 KiB
JavaScript
Raw Normal View History

2023-03-03 19:19:06 +00:00
const kExportAllInOne = false
const kInMicrosoftRetardationMode = true // change to false under our internal fork of typescript
2023-03-03 19:19:06 +00:00
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 == "this") return "_this"
if (name == "async") return "_async"
2023-03-03 19:19:06 +00:00
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 isMemberBlacklisted(type, name) {
if (!kInMicrosoftRetardationMode) return false
return (type == "IconView" && name == "getCursor") ||
(type == "IconView" && name == "setCursor") ||
(type == "LinkButton" && name == "NewWithLabel")||
(type == "TreeView" && name == "getCursor") ||
(type == "TreeView" && name == "setCursor") ||
(type == "ControlBinding" && name == "getGValueArray")||
(type == "ControlBinding" && name == "getValue")||
(type == "ControlBinding" && name == "syncValues")||
(type == "ControlSource" && name == "getValue")||
(type == "AppLaunchContext" && name == "getDisplay")||
(type == "GhostPad" && name == "NewFromTemplate")||
(type == "GutterRenderer" && name == "activate") ||
(type == "GutterRenderer" && name == "parentInstance") ||
(type == "GutterRendererText" && name == "measure") ||
(type == "AppChooserDialog" && name == "New") ||
(type == "ColorChooserDialog" && name == "New") ||
(type == "ApplicationWindow" && name == "New") ||
(type == "FontChooserDialog" && name == "New") ||
(type == "GesturePan" && name == "New") ||
(type == "LinkButton" && name == "New") ||
(type == "MountOperation" && name == "New") ||
(type == "InetAddress" && name == "New") ||
(type == "Mark" && name == "New") ||
(type == "GhostPad" && name == "New")||
(type == "LockButton" && name == "New") ||
(type == "ProxyAddress" && name == "New") ||
(type == "ThreadedSocketService" && name == "New") ||
(type == "Socket" && name == "receiveMessages") ||
(type == "Socket" && name == "sendMessages") ||
(type == "Socket" && name == "conditionWait")
}
2023-03-03 19:19:06 +00:00
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 | bigint"; break; }
case AuGlib.GITypeTag.GI_TYPE_TAG_UINT64 : { buffer += "number | bigint"; break; }
2023-03-03 19:19:06 +00:00
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, parent) {
let name = method.getMemberNameLocalized ? method.getMemberNameLocalized() : AuGlib.LocalizeCSymbolMember(method.asBase().getName(), null)
2023-03-03 19:19:06 +00:00
//if (name == "new") return
if (isMemberBlacklisted(parent, name))return
2023-03-03 19:19:06 +00:00
if (!method.isMethod())
buffer += "static ";
buffer += sanitize(name)
buffer += "("
let i2 = 0
let bOptMode = false
2023-03-03 19:19:06 +00:00
for (let i = 0; i < method.getNArgs(); i++) {
let arg = method.getArg(i);
if (arg.getType().getTag() == AuGlib.GITypeTag.GI_TYPE_TAG_VOID) continue;
if ((i2++) != 0) buffer += ", "
buffer += sanitize(AuGlib.LocalizeCSymbolMember(arg.asBase().getName(), null))
if (arg.isOptional() || bOptMode) {
buffer += " ?"
bOptMode = true
}
buffer += ": "
2023-03-03 19:19:06 +00:00
dumpType("", arg.getType())
if (arg.maybeNull())
buffer += " | undefined | null"
2023-03-03 19:19:06 +00:00
}
buffer += "): "
dumpType("", method.getReturnType())
}
function dumpFunction(method) {
buffer += "("
let i2 = 0
let bOptMode = false
2023-03-03 19:19:06 +00:00
for (let i = 0; i < method.getNArgs(); i++) {
let arg = method.getArg(i);
if (arg.getType().getTag() == AuGlib.GITypeTag.GI_TYPE_TAG_VOID) continue;
if ((i2++) != 0) buffer += ", "
buffer += sanitize(AuGlib.LocalizeCSymbolMember(arg.asBase().getName(), null))
if (arg.isOptional() || bOptMode) {
buffer += " ?"
bOptMode = true
}
buffer += ": "
2023-03-03 19:19:06 +00:00
dumpType("", arg.getType())
if (arg.maybeNull())
buffer += " | undefined | null"
2023-03-03 19:19:06 +00:00
}
buffer += ") => "
dumpType("", method.getReturnType())
}
function dumpInterfaces(namespace, objs, fuckTSMode, known) {
if (fuckTSMode) objs = [objs]
known = known ?? {}
2023-03-03 19:19:06 +00:00
objs.forEach((iface) => {
let name = iface.asBase().getName()
if (!fuckTSMode)
buffer += "\tclass " + name + " {\n"
2023-03-03 19:19:06 +00:00
let consts = iface.getConstants()
if (consts.length) {
consts.forEach((constant) => {
known[constant.getMemberNameLocalized()] = 1
dumpConstants(namespace, constant, "\t")
})
buffer += "\n"
}
let properties = iface.getProperties()
if (properties.length) {
properties.forEach((field) => {
if (known[field.getMemberNameLocalized()]) return
known[field.getMemberNameLocalized()] = 1
dumpField(namespace, field, "\t", name)
})
buffer += "\n"
}
2023-03-03 19:19:06 +00:00
iface.getMethods().forEach((method) => {
if (known[method.getMemberNameLocalized()]){
return
}
buffer += "\t\t"
dumpMethod(method, iface.asBase().getName())
2023-03-03 19:19:06 +00:00
buffer += ";\n"
})
if (!fuckTSMode)
2023-03-03 19:19:06 +00:00
buffer += "\t}\n\n"
})
}
function dumpField(namespace, constant, preface, parent) {
let name = sanitize(constant.getMemberNameLocalized())
if (isMemberBlacklisted(parent, name))return
2023-03-03 19:19:06 +00:00
var start = buffer.length
buffer += "\t\t" + name + " : "
2023-03-03 19:19:06 +00:00
var len = buffer.length
dumpType(namespace, constant.getType())
if (isInvalidType(buffer.substr(len))) {
buffer = buffer.substr(0, start)
} else{
buffer += ";\n"
}
}
function dumpInherit(namespace, prereqs, known) {
prereqs.forEach((iface) => {
dumpInterfaces(namespace, iface, true, known);
})
}
function dumpImpls(namespace, prereqs) {
let buffer = ""
prereqs.forEach((item) => {
if (buffer.length) {
buffer += ", "
} else {
buffer += " implements "
}
buffer += getNamespace(item.asBase().getNamespace()) + "." + item.asBase().getName()
})
return buffer
}
function dumpEventListener() {
buffer +=
`
\tclass EventListener {
\t\tdisconnect(): void
\t\tgetSignals(): string[]
\t}\n`
if (kInMicrosoftRetardationMode) {
buffer += `
\tclass IEventListener {}
`
}
}
2023-03-03 19:19:06 +00:00
function dumpObjects(namespace, objs) {
2023-03-03 19:19:06 +00:00
objs.forEach((obj) => {
let name = obj.asBase().getName()
if (isBlackListed(name)) {
buffer += "\tclass " + name + " { /*unsupported*/ }\n\n"
return
}
let signals = obj.getSignals()
let interfaces = obj.getInterfaces()
let suffix = ""
let parent = obj.getParent()
if (parent) {
suffix = " extends " + getNamespace(parent.asBase().getNamespace()) + "." + parent.asBase().getName()
}
if (interfaces.length) {
suffix += dumpImpls(namespace, interfaces)
}
buffer += "\tclass " + name + suffix + " {\n"
2023-03-03 19:19:06 +00:00
let consts = obj.getConstants()
if (consts.length) {
consts.forEach((constant) => {
dumpConstants(namespace, constant, "\t")
})
buffer += "\n"
}
buffer += "\t\tconstructor(initializerList ?: " + name + "Ctor" + ");\n\n"
2023-03-03 19:19:06 +00:00
let known = {}
while (parent) {
parent.getMethods().forEach((method) => {
known[method.getMemberNameLocalized()] = 1
})
parent.getInterfaces().forEach((iface) => {
iface.getMethods().forEach((method) => {
known[method.getMemberNameLocalized()] = 1
})
})
parent = parent.getParent()
}
let fields = obj.getFields()
2023-03-03 19:19:06 +00:00
if (fields.length) {
fields.forEach((field) => {
known[field.getMemberNameLocalized()] = 1
dumpField(namespace, field, "\t", name)
})
buffer += "\n"
}
let properties = obj.getProperties()
if (properties.length) {
properties.forEach((field) => {
if (known[field.getMemberNameLocalized()]) return
known[field.getMemberNameLocalized()] = 1
dumpField(namespace, field, "\t", name)
2023-03-03 19:19:06 +00:00
})
buffer += "\n"
}
obj.getMethods().forEach((method) => {
if (known[method.getMemberNameLocalized()]){
return
}
known[method.getMemberNameLocalized()] = 1
2023-03-03 19:19:06 +00:00
buffer += "\t\t"
var len = buffer.length
dumpMethod(method, name)
2023-03-03 19:19:06 +00:00
if (buffer.length == len) {
buffer = buffer.substr(0, buffer.length - 2)
} else{
buffer += ";\n"
}
})
if (kInMicrosoftRetardationMode &&
name == "Socket") {
buffer += `
\t\tconditionWait(condition: AuGlibEx.IOCondition,timeout: number|bigint,cancellable: Cancellable|null|undefined): boolean;
\t\treceiveMessages(messages: InputMessage[],numMessages: number,flags: number,timeout: number|bigint,cancellable: Cancellable|null|undefined): number;
\t\tsendMessages(messages: OutputMessage[],numMessages: number,flags: number,timeout: number|bigint,cancellable: Cancellable|null|undefined): number;`
}
if (name == "Application" && namespace == "Gtk") {
buffer += "\t\tstart(): void;\n"
buffer += "\t\tstop(): void;\n"
}
if (signals.length && !kInMicrosoftRetardationMode) {
buffer += "\t\tattachEventListener(listener: " + name + "EventListener): AuGlibEx.EventListener;\n\n"
}
if (kInMicrosoftRetardationMode) {
if (name == "Object" && obj.asBase().getNamespace() == "GObject") {
buffer += "\t\tattachEventListener(listener: AuGlibEx.IEventListener): AuGlibEx.EventListener;\n\n"
}
}
if (kInMicrosoftRetardationMode) {
buffer += "\t\t//TypeScript is complete garbage: \n"
dumpInherit(namespace, interfaces, known)
}
2023-03-03 19:19:06 +00:00
buffer += "\t}\n\n"
buffer += "\tclass " + name + "Ctor {\n"
obj.getStaticProperties().forEach((items) => {
let property = items[0]
let gtype = items[1]
buffer += "\t\t"
buffer += property
buffer += " ?: "
switch (Number(gtype))
{
case AuGlib.GType.G_TYPE_INTERFACE :
case AuGlib.GType.G_TYPE_INVALID :
case AuGlib.GType.G_TYPE_NONE :
break
case AuGlib.GType.G_TYPE_BOOLEAN :
buffer += "boolean"
break
case AuGlib.GType.G_TYPE_FLOAT :
case AuGlib.GType.G_TYPE_CHAR :
case AuGlib.GType.G_TYPE_UCHAR :
case AuGlib.GType.G_TYPE_INT :
case AuGlib.GType.G_TYPE_UINT :
case AuGlib.GType.G_TYPE_LONG :
case AuGlib.GType.G_TYPE_ULONG :
case AuGlib.GType.G_TYPE_ENUM :
case AuGlib.GType.G_TYPE_FLAGS :
case AuGlib.GType.G_TYPE_DOUBLE :
case AuGlib.GType.G_TYPE_UINT64 :
buffer += "number"
break
case AuGlib.GType.G_TYPE_POINTER :
case AuGlib.GType.G_TYPE_INT64 :
case AuGlib.GType.G_TYPE_UINT64 :
buffer += "number | bigint"
break
case AuGlib.GType.G_TYPE_STRING :
buffer += "string"
break
case AuGlib.GType.G_TYPE_BOXED :
case AuGlib.GType.G_TYPE_PARAM :
case AuGlib.GType.G_TYPE_VARIANT :
buffer += "any"
break
default:
{
let type = repo.findByGType(gtype)
if (type)
buffer += getNamespace(type.getNamespace()) + "." + type.getName()
else
buffer += "any"
break
}
}
buffer += ";\n"
})
buffer += "\t}\n\n"
if (signals.length) {
buffer += "\tclass " + name + "EventListener " + (kInMicrosoftRetardationMode ? "extends AuGlibEx.IEventListener " : "") + "{\n"
signals.forEach((signal) => {
buffer += "\t\t"
var len = buffer.length
dumpMethod(signal, name)
if (buffer.length == len) {
buffer = buffer.substr(0, buffer.length - 2)
} else{
buffer += ";\n"
}
})
buffer += "\t}\n\n"
}
2023-03-03 19:19:06 +00:00
})
}
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
2023-03-03 19:19:06 +00:00
buffer += "\t\t"
dumpMethod(method, name)
2023-03-03 19:19:06 +00:00
buffer += ";\n"
})
buffer += "\t}\n\n"
})
}
function printOptNewline(array) {
2023-03-03 19:19:06 +00:00
if (buffer[buffer.length - 1] != '\n') buffer += "\n"
if (array && array.length) buffer += "\n"
2023-03-03 19:19:06 +00:00
}
function dumpNamespace(namespace) {
let infos = repo.getInfos(namespace);
2023-03-03 19:19:06 +00:00
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(constants)
2023-03-03 19:19:06 +00:00
dumpEnums(namespace, enums)
if (namespace == "GLib") {
dumpEventListener()
}
printOptNewline(enums)
2023-03-03 19:19:06 +00:00
dumpInterfaces(namespace, interfaces)
printOptNewline(interfaces)
2023-03-03 19:19:06 +00:00
dumpStructs(namespace, structs)
printOptNewline(structs)
2023-03-03 19:19:06 +00:00
dumpObjects(namespace, objects)
buffer = buffer.substr(0, buffer.length - 1)
buffer += "}"
if (!kExportAllInOne) {
AuFS.WriteString(`./Export/${namespace}.d.ts`, buffer)
buffer = ""
} else {
buffer += "\n"
2023-03-03 19:19:06 +00:00
}
}
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)
}