UNPKG

node-gtk

Version:

GNOME Gtk+ bindings for NodeJS

671 lines (554 loc) 21.5 kB
const chalk = require('chalk') const internal = require('./native.js') const gi = require('../lib/index'); gi.startLoop(); const infos = [] const GI = gi._GIRepository; function def(obj, name, data) { Object.defineProperty(obj, name, { enumerable: false, configurable: true, value: data }); } const obj = () => Object.create(null); const name = (info) => GI.BaseInfo_get_name.call(info); const namespace = (info) => GI.BaseInfo_get_namespace.call(info); const getInfoType = (info) => GI.BaseInfo_get_type.call(info); const tag = (type_info) => GI.type_info_get_tag(type_info); const isDeprecated = (info) => GI.BaseInfo_is_deprecated.call(info) const infoTypeString = (type_info) => { const tag = GI.type_info_get_tag(type_info) if (tag !== GI.TypeTag.INTERFACE) return GI.type_tag_to_string(tag) const interfaceInfo = GI.type_info_get_interface(type_info) const interfaceInfoType = getInfoType(interfaceInfo) return GI.info_type_to_string(interfaceInfoType) + '.' + name(interfaceInfo) } function gtype(info) { const type_name = GI.registered_type_info_get_type_name(info); if (type_name === '') return null; else return GI.registered_type_info_get_g_type(info); } function isNoArgsConstructor(info) { const flags = GI.function_info_get_flags(info) return ((flags & GI.FunctionInfoFlags.IS_CONSTRUCTOR) != 0 && GI.callable_info_get_n_args(info) == 0) } function isConstructor(info) { const flags = GI.function_info_get_flags(info) return (flags & GI.FunctionInfoFlags.IS_CONSTRUCTOR) != 0 } function findBoxedConstructor(info, parent) { const type = getInfoType(info) let result = null if (type === GI.InfoType.UNION) { const n_methods = GI.union_info_get_n_methods (info); for (let i = 0; i < n_methods; i++) { const fn_info = GI.union_info_get_method (info, i); if (isNoArgsConstructor (fn_info)) { result = fn_info; break; } } if (!result) { for (let i = 0; i < n_methods; i++) { const fn_info = GI.union_info_get_method (info, i); if (name(fn_info) === 'new') { result = fn_info; break; } } } if (!result) { for (let i = 0; i < n_methods; i++) { const fn_info = GI.union_info_get_method (info, i); if (isConstructor (fn_info)) { result = fn_info; break; } } } } else { const n_methods = GI.struct_info_get_n_methods (info); for (let i = 0; i < n_methods; i++) { const fn_info = GI.struct_info_get_method (info, i); if (isNoArgsConstructor (fn_info)) { result = fn_info; break; } } if (!result) { for (let i = 0; i < n_methods; i++) { const fn_info = GI.struct_info_get_method (info, i); if (name(fn_info) === 'new') { result = fn_info; break; } } } if (!result) { for (let i = 0; i < n_methods; i++) { const fn_info = GI.struct_info_get_method (info, i); if (isConstructor (fn_info)) { result = fn_info; break; } } } } if (result) return new FunctionInfo(result, parent) return null } function BaseInfo(info, parent) { def(this, '_info', info); def(this, '_type', getInfoType(info)); // info_type def(this, '_ns', namespace(info)); this.infoType = GI.info_type_to_string(this._type); if (this._type != GI.InfoType.TYPE) this.name = name(info); if (parent) this.parent = parent if (isDeprecated(info)) this.isDeprecated = true infos.push(this) } function TypeInfo(info) { BaseInfo.call(this, info) def(this, '_tag', tag(info)); if (this._tag == GI.TypeTag.ARRAY) { this.type = infoTypeString(info); this.array_type = GI.ArrayType[GI.type_info_get_array_type(info)]; this.zero_terminated = GI.type_info_is_zero_terminated(info); this.fixed_size = GI.type_info_get_array_fixed_size(info); this.size = internal.GetTypeSize(info); const isPointer = GI.type_info_is_pointer(info) if (isPointer) this.isPointer = isPointer this.elementType = new TypeInfo(GI.type_info_get_param_type(info, 0)); } else if (this._tag == GI.TypeTag.GLIST || this._tag == GI.TypeTag.GSLIST) { this.type = infoTypeString(info); const isPointer = GI.type_info_is_pointer(info) if (isPointer) this.isPointer = isPointer this.elementType = new TypeInfo(GI.type_info_get_param_type(info, 0)); } else if (this._tag == GI.TypeTag.GHASH) { this.type = infoTypeString(info); const isPointer = GI.type_info_is_pointer(info) if (isPointer) this.isPointer = isPointer this.elementType = new TypeInfo(GI.type_info_get_param_type(info, 0)); } else if (this._tag == GI.TypeTag.INTERFACE) { const interface = GI.type_info_get_interface(info) const infoType = GI.BaseInfo_get_type.call(interface) this.type = infoTypeString(info) const isPointer = GI.type_info_is_pointer(info) if (isPointer) this.isPointer = isPointer if (infoType === GI.InfoType.CALLBACK) { this.callback = new FunctionInfo(interface, this) } } else { this.type = infoTypeString(info); this.size = internal.GetTypeSize(info); const isPointer = GI.type_info_is_pointer(info) if (isPointer) this.isPointer = isPointer } } function ConstantInfo(info, parent) { BaseInfo.call(this, info, parent) this.value = internal.GetConstantValue(info); } function ValueInfo (info, parent) { BaseInfo.call(this, info) this.value = GI.value_info_get_value(info) } function PropInfo(info, parent) { BaseInfo.call(this, info, parent) def(this, '_flags', GI.property_info_get_flags(info)); def(this, '_typeInfo', GI.property_info_get_type(info)); def(this, '_tag', tag(this._typeInfo)); this.type = infoTypeString(this._typeInfo); const transfer = GI.property_info_get_ownership_transfer(info); this.transfer = GI.Transfer[transfer]; } function FieldInfo(info, parent) { BaseInfo.call(this, info, parent) def(this, '_flags', GI.field_info_get_flags(info)); def(this, '_offset', GI.field_info_get_offset(info)); def(this, '_size', GI.field_info_get_size(info)); def(this, '_typeInfo', GI.field_info_get_type(info)); def(this, '_tag', tag(this._typeInfo)); this.type = infoTypeString(this._typeInfo); const readable = this._flags & GI.FieldInfoFlags.READABLE; if (readable == 0) this.readable = false; const writable = this._flags & GI.FieldInfoFlags.WRITABLE; if (writable == 0) this.writable = false; } function StructInfo(info, parent) { BaseInfo.call(this, info, parent) this.gtype = gtype(info); this.size = GI.struct_info_get_size(info); this.alignment = GI.struct_info_get_alignment(info); this.is_gtype_struct = GI.struct_info_is_gtype_struct(this._info) this.is_foreign = GI.struct_info_is_foreign(this._info) this.constructor = findBoxedConstructor(info, this) this.methods = obj(); this.fields = obj(); const n_methods = GI.struct_info_get_n_methods(info); for (let i = 0; i < n_methods; i++) { const method = GI.struct_info_get_method(info, i); const methodName = name(method); this.methods[methodName] = new FunctionInfo(method, this); } const n_fields = GI.struct_info_get_n_fields(info); for (let i = 0; i < n_fields; i++) { const field = GI.struct_info_get_field(info, i); const fieldName = name(field); this.fields[fieldName] = new FieldInfo(field, this); } } function UnionInfo(info, parent) { BaseInfo.call(this, info, parent) this.gtype = gtype(info); this.size = GI.union_info_get_size(info); this.alignment = GI.union_info_get_alignment(info); let is_discriminated = GI.union_info_is_discriminated(info); if (is_discriminated) { this.discriminator_type = new TypeInfo(GI.union_info_get_discriminator_type(info)); this.discriminator_offset = GI.union_info_get_discriminator_offset(info); } this.constructor = findBoxedConstructor(info, this) this.methods = {}; this.fields = {}; const n_methods = GI.union_info_get_n_methods(info); for (let i = 0; i < n_methods; i++) { const method = GI.union_info_get_method(info, i); const methodName = name(method); this.methods[methodName] = new FunctionInfo(method, this); } const n_fields = GI.union_info_get_n_fields(info); for (let i = 0; i < n_fields; i++) { const field = GI.union_info_get_field(info, i); const fieldName = name(field); this.fields[fieldName] = new FieldInfo(field, this); if (is_discriminated) { const d = GI.union_info_get_discriminator(info, i); this.fields[fieldName].discriminator = internal.GetConstantValue(d); } } } function EnumInfo(info, parent) { BaseInfo.call(this, info, parent) this.gtype = gtype(info); this.values = obj(); this.methods = obj(); const n_values = GI.enum_info_get_n_values(info); for (let i = 0; i < n_values; i++) { const valueInfo = GI.enum_info_get_value(info, i); const valueName = name(valueInfo); this.values[valueName] = new ValueInfo(valueInfo, this); } const n_methods = GI.enum_info_get_n_methods(info); for (let i = 0; i < n_methods; i++) { const method = GI.enum_info_get_method(info, i); const methodName = name(method); this.methods[methodName] = new FunctionInfo(method, this); } } function InterfaceInfo(info, parent) { BaseInfo.call(this, info, parent) this.gtype = gtype(info); const structInfo = GI.interface_info_get_iface_struct(info) if (structInfo !== null) this.iface_struct = new StructInfo(structInfo, this); this.prerequisites = obj(); this.properties = obj(); this.methods = obj(); this.signals = obj(); this.vfuncs = obj(); this.constants = obj(); const n_prerequisites = GI.interface_info_get_n_prerequisites(info); for (let i = 0; i < n_prerequisites; i++) { const prerequisite = GI.interface_info_get_prerequisite(info, i); const prerequisiteName = name(prerequisite); this.prerequisites[prerequisiteName] = getInfo(prerequisite); } const n_properties = GI.interface_info_get_n_properties(info); for (let i = 0; i < n_properties; i++) { const property = GI.interface_info_get_property(info, i); const propertyName = name(property); this.properties[propertyName] = getInfo(property, this); } const n_methods = GI.interface_info_get_n_methods(info); for (let i = 0; i < n_methods; i++) { const method = GI.interface_info_get_method(info, i); const methodName = name(method); this.methods[methodName] = getInfo(method, this); } const n_signals = GI.interface_info_get_n_signals(info); for (let i = 0; i < n_signals; i++) { const signal = GI.interface_info_get_signal(info, i); const signalName = name(signal); this.signals[signalName] = signal; } const n_vfuncs = GI.interface_info_get_n_vfuncs(info); for (let i = 0; i < n_vfuncs; i++) { const vfuncInfo = GI.interface_info_get_vfunc(info, i); const vfuncName = name(vfuncInfo); this.vfuncs[vfuncName] = getInfo(vfuncInfo, this); } const n_constants = GI.interface_info_get_n_constants(info); for (let i = 0; i < n_constants; i++) { const constant = GI.interface_info_get_constant(info, i); const constantName = name(constant); this.constants[constantName] = getInfo(constant); } } function ObjectInfo(info, parent) { BaseInfo.call(this, info, parent) this.gtype = gtype(info); const parentInfo = GI.object_info_get_parent(info) if (parentInfo) def(this, '_parent', new ObjectInfo(parentInfo, parent)); this.constants = obj(); this.fields = obj(); this.interfaces = obj(); this.methods = obj(); this.properties = obj(); this.signals = obj(); this.vfuncs = obj(); const n_properties = GI.object_info_get_n_properties(info); for (let i = 0; i < n_properties; i++) { const propertyInfo = GI.object_info_get_property(info, i); const propertyName = name(propertyInfo); this.properties[propertyName] = getInfo(propertyInfo, this); } const n_constants = GI.object_info_get_n_constants(info); for (let i = 0; i < n_constants; i++) { const constantInfo = GI.object_info_get_constant(info, i); const constantName = name(constantInfo); this.constants[constantName] = getInfo(constantInfo, this); } const n_interfaces = GI.object_info_get_n_interfaces(info); for (let i = 0; i < n_interfaces; i++) { const i_info = GI.object_info_get_interface(info, i); const i_name = name(i_info); this.interfaces[i_name] = new InterfaceInfo(i_info, this); } const n_methods = GI.object_info_get_n_methods(info); for (let i = 0; i < n_methods; i++) { const methodInfo = GI.object_info_get_method(info, i); const methodName = name(methodInfo); this.methods[methodName] = new FunctionInfo(methodInfo, this); } const n_signals = GI.object_info_get_n_signals(info); for (let i = 0; i < n_signals; i++) { const signalInfo = GI.object_info_get_signal(info, i); const signalName = name(signalInfo); this.signals[signalName] = getInfo(signalInfo, this); } const n_vfuncs = GI.object_info_get_n_vfuncs(info); for (let i = 0; i < n_vfuncs; i++) { const vfuncInfo = GI.object_info_get_vfunc(info, i); const vfuncName = name(vfuncInfo); this.vfuncs[vfuncName] = getInfo(vfuncInfo, this); } } function ArgInfo(info, parent) { BaseInfo.call(this, info, parent) def(this, '_typeInfo', GI.arg_info_get_type(info)); def(this, '_tag', tag(this._typeInfo)); this.typeName = infoTypeString(this._typeInfo); this.type = new TypeInfo(this._typeInfo); this.name = name(info); this.direction = GI.Direction[GI.arg_info_get_direction(info)]; this.transfer = GI.Transfer[GI.arg_info_get_ownership_transfer(info)]; const may_be_null = GI.arg_info_may_be_null(info); if (may_be_null) this.nullable = may_be_null; const is_caller_allocates = GI.arg_info_is_caller_allocates(info); if (is_caller_allocates) this.caller_allocates = true; const is_return_value = GI.arg_info_is_return_value(info); if (is_return_value) this.return_value = true; const is_skip = GI.arg_info_is_skip(info); if (is_skip) this.skip = true; const length_pos = GI.type_info_get_array_length(this._typeInfo) if (length_pos >= 0) this.lengthPos = length_pos this.parent = parent } function CallableInfo(info, parent) { BaseInfo.call(this, info, parent) this.n_args = GI.callable_info_get_n_args(info); this.args = []; for (let i = 0; i < this.n_args; i++) { this.args[i] = new ArgInfo(GI.callable_info_get_arg(info, i), this); } for (let i = 0; i < this.n_args; i++) { if (this.args[i].lengthPos !== undefined) this.args[this.args[i].lengthPos].isArrayLength = true } const transfer = GI.callable_info_get_caller_owns(info); this.transfer = GI.Transfer[transfer]; const return_type = GI.callable_info_get_return_type(info); this.return_type = new TypeInfo(return_type); this.return_tag = infoTypeString(return_type); const mayReturnNull = GI.callable_info_may_return_null(info); if (mayReturnNull) this.mayReturnNull = true; const skipReturn = GI.callable_info_skip_return(info) if (skipReturn) this.skipReturn = true; const canThrow = GI.callable_info_can_throw_gerror(info) if (canThrow) this.canThrow = true } function SignalInfo(info, parent) { BaseInfo.call(this, info, parent) CallableInfo.call(this, info); def(this, '_flags', GI.signal_info_get_flags(info)); } function VFuncInfo(info, parent) { BaseInfo.call(this, info, parent) CallableInfo.call(this, info); const invoker = GI.vfunc_info_get_invoker(info); if (invoker) this.invoker = new FunctionInfo(invoker, this); const signal = GI.vfunc_info_get_signal(info); if (signal) this.signal = new SignalInfo(signal, this); } function FunctionInfo(info, parent) { BaseInfo.call(this, info, parent) CallableInfo.call(this, info); if (this.infoType === 'callback') return this.symbol = GI.function_info_get_symbol(info) def(this, '_flags', GI.function_info_get_flags(info)); this.isMethod = (this._flags & GI.FunctionInfoFlags.IS_METHOD) !== 0 this.isConstructor = (this._flags & GI.FunctionInfoFlags.IS_CONSTRUCTOR) !== 0 this.isGetter = (this._flags & GI.FunctionInfoFlags.IS_GETTER) !== 0 this.isSetter = (this._flags & GI.FunctionInfoFlags.IS_SETTER) !== 0 } function parseNamespace(ns, ver) { const module = Object.create(null); const repo = GI.Repository_get_default(); if (!gi.isLoaded(ns, ver)) GI.Repository_require.call(repo, ns, ver, 0); const nInfos = GI.Repository_get_n_infos.call(repo, ns); for (let i = 0; i < nInfos; i++) { const info = GI.Repository_get_info.call(repo, ns, i); const baseinfo = getInfo(info, ns); const basename = name(info); module[basename] = baseinfo; } return module; } function getInfo (info, parent) { switch (getInfoType(info)) { case GI.InfoType.INVALID: return null; case GI.InfoType.CALLBACK: case GI.InfoType.FUNCTION: return new FunctionInfo(info, parent) case GI.InfoType.OBJECT: return new ObjectInfo(info, parent) case GI.InfoType.ENUM: case GI.InfoType.FLAGS: return new EnumInfo(info, parent) case GI.InfoType.BOXED: case GI.InfoType.STRUCT: return new StructInfo(info, parent) case GI.InfoType.UNION: return new UnionInfo(info, parent) case GI.InfoType.INTERFACE: return new InterfaceInfo(info, parent) case GI.InfoType.CONSTANT: return new ConstantInfo(info, parent) case GI.InfoType.FIELD: return new FieldInfo(info, parent) case GI.InfoType.PROPERTY: return new PropInfo(info, parent) case GI.InfoType.ARG: return new ArgInfo(info, parent) case GI.InfoType.TYPE: return new TypeInfo(info) case GI.InfoType.VALUE: return new ValueInfo(info, parent) case GI.InfoType.SIGNAL: return new SignalInfo(info, parent) case GI.InfoType.VFUNC: return new VFuncInfo(info, parent) case GI.InfoType.UNRESOLVED: return undefined; } return new BaseInfo(info, parent) } function getLibs() { let paths = GI.Repository_get_search_path() .map(p => require('fs').readdirSync(p)); let files = [].concat(...paths) .filter(f => f.endsWith('.typelib')) .map(f => f.replace(/\.typelib/, '')) .map(f => [f].concat(f.split('-'))); return files; } function formatName(info) { let name = '' let current = info while (current) { name = (current.name || current) + (name ? '.' + name : '') current = current.parent } return name } function formatFunction(fn) { const parent = formatName(fn.parent) return ( (parent ? chalk.yellow(parent) + chalk.grey('.') : '') + chalk.bold(fn.name) + chalk.grey(' (') + fn.args.map(a => a.name + ': ' + formatType(a.type) + (a.direction !== 'IN' ? chalk.magenta(a.direction) : '') + (a.transfer !== 'NOTHING' ? chalk.blue(a.transfer.charAt(0)) : '') ).join(chalk.grey(', ')) + chalk.grey('): ') + formatType(fn.return_type) ) } function formatType(type) { if (type.type === 'array') return formatType(type.elementType) + '[]' if (type.type === 'glist' || type.type === 'gslist') return [ chalk.yellow('List'), chalk.grey('<'), formatType(type.elementType), chalk.grey('>'), ].join('') return chalk.yellow(type.type) } module.exports = { parseNamespace, getLibs, infos, formatName, formatFunction, formatType, };