UNPKG

@ts-for-gir/lib

Version:

Typescript .d.ts generator from GIR for gjs

866 lines 36 kB
import { Logger } from "../logger.js"; import { FormatGenerator } from "./generator.js"; import { IntrospectedBaseClass, IntrospectedRecord, IntrospectedInterface, IntrospectedClass } from "../gir/class.js"; import { IntrospectedConstant } from "../gir/const.js"; import { IntrospectedEnum, IntrospectedError } from "../gir/enum.js"; import { IntrospectedSignalType } from "../gir/signal.js"; import { IntrospectedFunction, IntrospectedConstructor, IntrospectedFunctionParameter, IntrospectedCallback } from "../gir/function.js"; import { IntrospectedClassFunction, IntrospectedStaticClassFunction, IntrospectedVirtualClassFunction } from "../gir/function.js"; import { sanitizeIdentifierName, isInvalid, resolveDirectedType } from "../gir/util.js"; import { NativeType, AnyType, VoidType, StringType, NumberType, ArrayType, TypeIdentifier, OrType, TupleType, NullableType, ClosureType, AnyFunctionType, TypeConflict } from "../gir.js"; import { GirDirection } from "@gi.ts/parser"; import { IntrospectedAlias } from "../gir/alias.js"; function generateType(type) { if (type instanceof TypeIdentifier) { return { kind: "identifier" /* TypeKind.identifier */, name: type.name, namespace: type.namespace }; } else if (type instanceof NativeType) { return { kind: "native" /* TypeKind.native */, type: type.expression() }; } else if (type instanceof ClosureType) { return { kind: "closure" /* TypeKind.closure */, type: generateType(type.type), user_data: type.user_data }; } else if (type instanceof ArrayType) { return { kind: "array" /* TypeKind.array */, type: generateType(type.type), depth: type.arrayDepth }; } else if (type instanceof NullableType) { return { kind: "null" /* TypeKind.nulled */, type: generateType(type.type) }; } else if (type instanceof TypeConflict) { // Type conflicts aren't considered in JSON outputs. return generateType(type.type); } else if (type instanceof TupleType) { return { kind: "tuple" /* TypeKind.tuple */, types: type.types.map(t => generateType(t)) }; } else if (type instanceof OrType) { return { kind: "or" /* TypeKind.or */, types: type.types.map(t => generateType(t)) }; } else { return { kind: "native" /* TypeKind.native */, type: "any" }; } } function capitalize(str) { if (str.length === 0) { return ""; } if (str.length === 1) { return str[0].toUpperCase(); } return str[0].toUpperCase() + str.substring(1).toLowerCase(); } export class JsonGenerator extends FormatGenerator { log; constructor(namespace, options) { super(namespace, options); this.log = new Logger(options.verbose, JsonGenerator.name); } /** * Intelligently reformats # and () references * to handle c-prefixes and namespacing. * * @param doc */ generateDoc(doc) { const { namespace } = this; function resolveClass(ns, className) { let classes = ns.getMembers(className); let plural = false; if (classes.length === 0 && className.endsWith("Class")) { classes = ns.getMembers(className.slice(0, -5)); } if (classes.length === 0 && className.endsWith("Iface")) { classes = ns.getMembers(className.slice(0, -5)); } if (classes.length === 0 && className.endsWith("Interface")) { classes = ns.getMembers(className.slice(0, -9)); } if (classes.length === 0 && className.endsWith("s")) { plural = true; classes = ns.getMembers(className.slice(0, -1)); } return [classes[0] ?? null, plural]; } function formatReference(identifier, member_name, punc) { const parts = identifier .split(/([A-Z])/) .filter(p => p != "") .reduce((prev, next) => { if (next.toUpperCase() === next) { prev.push(`${next}`); } else { const lastCapital = prev.pop(); prev.push(`${lastCapital}${next}`); } return prev; }, []); const [base_part] = parts; const [, , namespaces, className] = parts.slice(1).reduce(([underscore, camel, ns, selected], next) => { const next_underscore = [underscore, next.toLowerCase()].join("_"); const namespaces = namespace.getImportsForCPrefix(next_underscore); const nextCamel = camel + capitalize(next); if (namespaces.length > 0) { return [next_underscore, nextCamel, namespaces, capitalize(next)]; } return [next_underscore, nextCamel, ns, selected + capitalize(next)]; }, [ base_part.toLowerCase(), capitalize(base_part), namespace.getImportsForCPrefix(base_part.toLowerCase()), "" ]); let ns = namespaces.find(n => n.hasSymbol(className)); if (!ns) { ns = namespaces.find(n => { const [c] = resolveClass(n, className); return c != null; }); } if (ns) { const is_prop = punc === ":"; const modified_name = is_prop ? member_name.replace(/[\-]/g, "_") : member_name; const [clazz, plural] = resolveClass(ns, className); if (clazz instanceof IntrospectedBaseClass || clazz instanceof IntrospectedEnum) { const r = `#${plural ? "{" : ""}${ns.namespace}.${clazz.name}${punc ? `${punc}${modified_name}` : ""}${plural ? "}s" : ""}`; return r; } return `#${ns.namespace}${punc ? ` (${punc}${modified_name})` : ""}`; } else { return null; } } function formatFunctionReference(func, upper = false) { // namespace_class_do_thing() const parts = func.toLowerCase().split("_"); // ['namespace', 'class', 'do', 'thing'] const [base_part] = parts; // ['namespace'] const namespaceBase = [ base_part.toLowerCase(), capitalize(base_part), namespace.getImportsForCPrefix(base_part.toLowerCase()), 0 ]; // ['namespace', 'Namespace', { Namespace }, -1] const [, , namespaces, i] = parts.slice(1).reduce(([prev, camel, currentNamespaces, selected], next, i) => { const underscore = [prev, next.toLowerCase()].join("_"); const namespaces = namespace.getImportsForCPrefix(underscore); const identifier = camel + capitalize(next); // We've found namespace(s) which matches the c_prefix if (namespaces.length > 0) { return [underscore, identifier, namespaces, i]; } return [underscore, identifier, currentNamespaces, selected]; }, namespaceBase); // If no namespaces are found for the function's c_prefix, we return the original reference. if (namespaces.length === 0) { return null; } // ['class', 'do', 'thing'] const nameParts = parts.slice(i + 1); // 'class_do_thing' const functionName = nameParts.join("_"); const functionNamespace = namespaces.find(n => n.hasSymbol(functionName.toLowerCase())); const constNamespace = namespaces.find(n => n.hasSymbol(functionName.toUpperCase())); const enumNamespace = namespaces.find(n => n.enum_constants.has(func.toUpperCase())); if (functionNamespace) { const [member = null] = functionNamespace.getMembers(functionName.toLowerCase()); if (member instanceof IntrospectedFunction) { return `${functionNamespace.namespace}.${member.name}`; } return null; } else if (constNamespace) { const [member = null] = constNamespace.getMembers(functionName.toUpperCase()); if (member instanceof IntrospectedConstant) { return `${constNamespace.namespace}.${member.name}`; } return null; } else if (enumNamespace) { const constantInfo = enumNamespace.enum_constants.get(func.toUpperCase()); if (constantInfo) { const [enumName, memberName] = constantInfo; const [klass = null] = enumNamespace.getMembers(enumName); if (klass instanceof IntrospectedEnum) { return `${enumNamespace.namespace}.${klass.name}.${memberName.toUpperCase()}`; } } return null; } else { // ['class', 'do', 'thing'] const { selectedClassName, resolvedNamespace, selectedIndex } = parts.slice(i + 1).reduce(({ className, selectedClassName, resolvedNamespace, selectedIndex }, next, i) => { // Class const identifier = `${className}${capitalize(next)}`; const withSymbol = namespaces.find(n => n.hasSymbol(identifier)); if (withSymbol) { // { className: Class, resolvedNamespace: {Namespace}, selectedIndex: 0 } return { className: identifier, selectedClassName: identifier, resolvedNamespace: withSymbol, selectedIndex: i }; } return { className: identifier, selectedClassName, resolvedNamespace, selectedIndex }; }, { className: "", selectedClassName: "", resolvedNamespace: null, selectedIndex: -1 }); if (resolvedNamespace && selectedIndex >= 0) { const nextIndex = i + selectedIndex + 1 /* (slice omits first index) */ + 1; /* (the next index) */ const functionName = parts.slice(nextIndex).join("_"); const [klass] = resolveClass(resolvedNamespace, selectedClassName); if (klass instanceof IntrospectedBaseClass || klass instanceof IntrospectedEnum) { return `${resolvedNamespace.namespace}.${klass.name}.${upper ? functionName.toUpperCase() : functionName}`; } return `${resolvedNamespace.namespace}.${selectedClassName}.${upper ? functionName.toUpperCase() : functionName}`; } } return null; } return `${doc}` .replace(/[#]{0,1}([A-Z][A-z]+)\.([a-z_]+)\(\)/g, (original, identifier, member_name) => { const resolved = formatReference(identifier, member_name, "."); return resolved != null ? `${resolved}()` : original; }) .replace(/#([A-Z][A-z]*)(([:]{1,2})([a-z\-]+)){0,1}/g, (original, identifier, _, punc, member_name) => { const resolved = formatReference(identifier, member_name, punc); return resolved != null ? resolved : original; }) .replace(/([A-Z][A-z]*)(([:]{1,2})([a-z\-]+))/g, (original, identifier, _, punc, member_name) => { const resolved = formatReference(identifier, member_name, punc); return resolved != null ? resolved : original; }) .replace(/(\s)([a-z_]+)\(\)/g, (original, w, func) => { const resolved = formatFunctionReference(func); return resolved != null ? `${w}${resolved}()` : original; }) .replace(/%([A-Z_]+)/g, (original, identifier) => { const resolved = formatFunctionReference(identifier.toLowerCase(), true); return resolved != null ? `%${resolved}` : original; }) .replace(/#([A-Z_]+)/g, (original, identifier) => { const resolved = formatFunctionReference(identifier.toLowerCase(), true); return resolved != null ? `#${resolved}` : original; }); } generateMetadata(metadata) { return { ...metadata }; } generateParameters(parameters) { const { namespace, options } = this; return parameters.map(p => ({ kind: "parameter" /* NodeKind.parameter */, direction: p.direction, optional: p.isOptional, varargs: p.isVarArgs, name: p.name, resoleNames: p.resolve_names, type: generateType(p.type.resolve(namespace, options)), ...this._generateDocAndMetadata(p) })); } generateCallbackType(node) { return [{}, {}]; } generateCallback(node) { const { namespace, options } = this; const parameters = this.generateParameters(node.parameters); return { kind: "callback" /* NodeKind.callback */, name: node.name, type: this.generateCallbackType(node), parameters, returnType: generateType(node.return().resolve(namespace, options)), ...this._generateDocAndMetadata(node) }; } generateClassCallback(node) { const { namespace, options } = this; const parameters = this.generateParameters(node.parameters); return { kind: "callback" /* NodeKind.callback */, name: node.name, type: this.generateCallbackType(node), parameters, returnType: generateType(node.return().resolve(namespace, options)), ...this._generateDocAndMetadata(node) }; } generateReturn(return_type, output_parameters) { const { namespace, options } = this; const type = return_type.resolve(namespace, options); if (output_parameters.length > 0) { const exclude_first = type.equals(VoidType); const returns = [ ...(exclude_first ? [] : [type]), ...output_parameters.map(op => op.type.resolve(namespace, options)) ]; return returns.map(r => generateType(r)); } return generateType(type); } generateEnum(node) { return { kind: "enum" /* NodeKind.enum */, name: node.name, members: Array.from(node.members.values()).map(member => member.asString(this)), ...this._generateDocAndMetadata(node) }; } generateError(node) { const { namespace } = this; const clazz = node.asClass(); clazz.members = []; clazz.members.push(...Array.from(node.functions.values())); const GLib = namespace.assertInstalledImport("GLib"); const GLibError = GLib.assertClass("Error"); clazz.superType = GLibError.getType(); // Manually construct a GLib.Error constructor. clazz.mainConstructor = new IntrospectedConstructor({ name: "new", parent: clazz, parameters: [ new IntrospectedFunctionParameter({ name: "options", type: NativeType.of("{ message: string, code: number}"), direction: GirDirection.In }) ], return_type: clazz.getType() }); return { ...clazz.asString(this), kind: "error" /* NodeKind.error */ }; } _generateDocAndMetadata(node) { const { options } = this; if (!options.noComments) { return { private: node.isPrivate, doc: this.generateDoc(node.doc ?? "") ?? null, metadata: this.generateMetadata(node.metadata ?? {}) ?? null }; } return { private: false, doc: null, metadata: null }; } generateConst(node) { const { namespace, options } = this; return { kind: "constant" /* NodeKind.constant */, name: node.name, type: generateType(node.type.resolve(namespace, options)), ...this._generateDocAndMetadata(node) }; } implements(node) { const { namespace, options } = this; if (node.interfaces.length > 0) { return node.interfaces .map(i => i.resolveIdentifier(namespace, options)) .filter((i) => i != null); } return []; } extends(node) { const { namespace: ns, options } = this; if (node.superType) { return node.superType.resolveIdentifier(ns, options); } return null; } generateInterface(node) { const { namespace } = this; // If an interface does not list a prerequisite type, we fill it with GObject.Object if (node.superType == null) { const gobject = namespace.assertInstalledImport("GObject"); // TODO Optimize GObject.Object if (!gobject) { throw new Error("GObject not generated, all interfaces extend from GObject.Object!"); } const GObject = gobject.getClass("Object"); if (!GObject) { throw new Error(`GObject.Object could not be found while generating ${node.namespace.namespace}.${node.name}`); } node.superType = GObject.getType(); } const { name } = node; const Extends = this.extends(node); const Properties = node.props.map(v => v && v.asString(this)); const Methods = node.members .filter(m => !(m instanceof IntrospectedStaticClassFunction) && !(m instanceof IntrospectedVirtualClassFunction)) .map(v => v && v.asString(this)); const StaticMethods = node.members .filter((m) => m instanceof IntrospectedStaticClassFunction) .map(v => v && v.asString(this)); const VirtualMethods = node.members .filter((m) => m instanceof IntrospectedVirtualClassFunction) .map(v => v && v.asString(this)); return { kind: "interface" /* NodeKind.interface */, name, type: generateType(node.getType()), extends: Extends ? generateType(Extends) : null, props: Properties, methods: Methods, staticMethods: StaticMethods, virtualMethods: VirtualMethods, ...this._generateDocAndMetadata(node) }; } generateRecord(node) { const { name } = node; const Extends = this.extends(node); const Properties = node.props.map(v => v && v.asString(this)); const Fields = node.fields.map(v => v && v.asString(this)); const Constructors = node.constructors.map(v => v && this.generateConstructorFunction(v)); const Methods = node.members .filter(m => !(m instanceof IntrospectedStaticClassFunction) && !(m instanceof IntrospectedVirtualClassFunction)) .map(v => v && v.asString(this)); const StaticMethods = node.members .filter((m) => m instanceof IntrospectedStaticClassFunction) .map(v => v && v.asString(this)); const VirtualMethods = node.members .filter((m) => m instanceof IntrospectedVirtualClassFunction) .map(v => v && v.asString(this)); const Callbacks = node.callbacks.map(c => c && c.asString(this)); return { kind: "record" /* NodeKind.record */, name, type: generateType(node.getType()), mainConstructor: node.mainConstructor?.asString(this) ?? null, extends: Extends ? generateType(Extends) : null, implements: [], props: Properties, fields: Fields, constructors: Constructors, methods: Methods, staticMethods: StaticMethods, virtualMethods: VirtualMethods, callbacks: Callbacks, ...this._generateDocAndMetadata(node) }; } generateClass(node) { const Extends = this.extends(node); const Implements = this.implements(node); let MainConstructor = null; const ConstructorProps = node.props.map(v => this.generateProperty(v, true)); if (node.mainConstructor) { MainConstructor = this.generateConstructor(node.mainConstructor); } else { MainConstructor = { kind: "properties_constructor" /* NodeKind.propertiesConstructor */, name: "new", private: false, properties: ConstructorProps.map(p => ({ kind: "parameter" /* NodeKind.parameter */, private: p.private, varargs: false, name: p.name, type: p.type, doc: p.doc, metadata: p.metadata, optional: true })), doc: null, metadata: null }; } const Properties = node.props.map(v => v.asString(this)); const Fields = node.fields.map(v => v.asString(this)); const Constructors = node.constructors.map(v => this.generateConstructorFunction(v)); const Methods = node.members .filter(m => !(m instanceof IntrospectedStaticClassFunction) && !(m instanceof IntrospectedVirtualClassFunction)) .map(v => v && v.asString(this)); const StaticMethods = node.members .filter((m) => m instanceof IntrospectedStaticClassFunction) .map(v => v && v.asString(this)); const VirtualMethods = node.members .filter((m) => m instanceof IntrospectedVirtualClassFunction) .map(v => v && v.asString(this)); // TODO Move these to a cleaner place. const Connect = new IntrospectedClassFunction({ name: "connect", parent: node, parameters: [ new IntrospectedFunctionParameter({ name: "id", type: StringType, direction: GirDirection.In }), new IntrospectedFunctionParameter({ name: "callback", type: AnyFunctionType, direction: GirDirection.In }) ], return_type: NumberType }); const ConnectAfter = new IntrospectedClassFunction({ name: "connect_after", parent: node, parameters: [ new IntrospectedFunctionParameter({ name: "id", type: StringType, direction: GirDirection.In }), new IntrospectedFunctionParameter({ name: "callback", type: AnyFunctionType, direction: GirDirection.In }) ], return_type: NumberType }); const Emit = new IntrospectedClassFunction({ name: "emit", parent: node, parameters: [ new IntrospectedFunctionParameter({ name: "id", type: StringType, direction: GirDirection.In }), new IntrospectedFunctionParameter({ name: "args", isVarArgs: true, type: new ArrayType(AnyType), direction: GirDirection.In }) ], return_type: VoidType }); const default_signals = []; let hasConnect, hasConnectAfter, hasEmit; if (node.signals.length > 0) { hasConnect = node.members.some(m => m.name === "connect"); hasConnectAfter = node.members.some(m => m.name === "connect_after"); hasEmit = node.members.some(m => m.name === "emit"); if (!hasConnect) { default_signals.push(Connect); } if (!hasConnectAfter) { default_signals.push(ConnectAfter); } if (!hasEmit) { default_signals.push(Emit); } hasConnect = !default_signals.some(s => s.name === "connect"); hasConnectAfter = !default_signals.some(s => s.name === "connect_after"); hasEmit = !default_signals.some(s => s.name === "emit"); } const SignalsList = [ ...default_signals.map(s => s.asString(this)), ...node.signals .map(s => { const methods = []; if (!hasConnect) methods.push(s.asString(this, IntrospectedSignalType.CONNECT)); if (!hasConnectAfter) methods.push(s.asString(this, IntrospectedSignalType.CONNECT_AFTER)); if (!hasEmit) methods.push(s.asString(this, IntrospectedSignalType.EMIT)); return methods; }) .flat() ]; const Signals = SignalsList; return { kind: "class" /* NodeKind.class */, abstract: node.isAbstract, type: generateType(node.getType()), name: node.name, mainConstructor: MainConstructor, signals: Signals, extends: Extends ? generateType(Extends) : null, implements: Implements.map(i => generateType(i)), props: Properties, fields: Fields, constructors: Constructors, methods: Methods, staticMethods: StaticMethods, virtualMethods: VirtualMethods, ...this._generateDocAndMetadata(node) }; } generateField(node) { const { namespace, options } = this; const { name, computed } = node; const invalid = isInvalid(name); const Static = node.isStatic; const ReadOnly = node.writable; return { kind: "field" /* NodeKind.field */, readonly: ReadOnly, static: Static, computed, type: generateType(node.type.resolve(namespace, options)), name: invalid ? `"${name}"` : name, ...this._generateDocAndMetadata(node) }; } generateProperty(node, construct = false) { const { namespace, options } = this; const invalid = isInvalid(node.name); const ReadOnly = node.writable || construct; const Name = invalid ? `"${node.name}"` : node.name; const Type = generateType(node.type.resolve(namespace, options)); return { kind: "prop" /* NodeKind.prop */, readonly: ReadOnly, constructOnly: node.constructOnly, readable: node.readable, writable: node.writable, static: false, type: Type, name: Name, ...this._generateDocAndMetadata(node) }; } generateSignal(node, type = IntrospectedSignalType.CONNECT) { switch (type) { case IntrospectedSignalType.CONNECT: return node.asConnect(false).asString(this); case IntrospectedSignalType.CONNECT_AFTER: return node.asConnect(true).asString(this); case IntrospectedSignalType.EMIT: return node.asEmit().asString(this); } } generateEnumMember(node) { const invalid = isInvalid(node.name); let enumMember; if (node.value != null && !Number.isNaN(Number.parseInt(node.value, 10)) && Number.isNaN(Number.parseInt(node.name, 10)) && node.name !== "NaN") { enumMember = { name: invalid ? `"${node.name}"` : `${node.name}`, value: `${node.value}` }; } else { enumMember = { name: invalid ? `"${node.name}"` : `${node.name}`, value: null }; } return { kind: "enum_member" /* NodeKind.enumMember */, ...enumMember, ...this._generateDocAndMetadata(node) }; } generateParameter(node) { const { namespace, options } = this; const type = generateType(resolveDirectedType(node.type, node.direction)?.resolve(namespace, options) ?? node.type.resolve(namespace, options)); return { kind: "parameter" /* NodeKind.parameter */, name: node.name, type, varargs: node.isVarArgs, optional: node.isOptional, ...this._generateDocAndMetadata(node) }; } generateFunction(node) { const { namespace } = this; // Register our identifier with the sanitized identifiers. // We avoid doing this in fromXML because other class-level function classes // depends on that code. sanitizeIdentifierName(namespace.namespace, node.raw_name); const Parameters = this.generateParameters(node.parameters); const ReturnType = this.generateReturn(node.return(), node.output_parameters); return { kind: "function" /* NodeKind.function */, name: node.name, parameters: Parameters, returnType: ReturnType, ...this._generateDocAndMetadata(node) }; } generateConstructorFunction(node) { const { namespace, options } = this; const Parameters = this.generateParameters(node.parameters); return { kind: "class_function" /* NodeKind.classFunction */, static: true, name: node.name, parameters: Parameters, returnType: generateType(node.return().resolve(namespace, options)), ...this._generateDocAndMetadata(node) }; } generateConstructor(node) { return { name: node.name, kind: "constructor" /* NodeKind.constructor */, parameters: this.generateParameters(node.parameters), ...this._generateDocAndMetadata(node) }; } generateDirectAllocationConstructor(node) { return { name: node.name, kind: "constructor" /* NodeKind.constructor */, parameters: this.generateParameters(node.parameters), ...this._generateDocAndMetadata(node) }; } generateClassFunction(node) { const parameters = node.parameters.map(p => this.generateParameter(p)); const output_parameters = node.output_parameters; const return_type = node.return(); const ReturnType = this.generateReturn(return_type, output_parameters); return { kind: "class_function" /* NodeKind.classFunction */, name: node.name, parameters, returnType: ReturnType, ...this._generateDocAndMetadata(node) }; } generateStaticClassFunction(node) { const parameters = node.parameters.map(p => this.generateParameter(p)); const output_parameters = node.output_parameters; const return_type = node.return(); const ReturnType = this.generateReturn(return_type, output_parameters); return { kind: "static_class_function" /* NodeKind.staticClassFunction */, name: node.name, parameters, returnType: ReturnType, ...this._generateDocAndMetadata(node) }; } generateAlias(node) { const { namespace, options } = this; const type = node.type.resolve(namespace, options); const { name } = node; return { kind: "alias" /* NodeKind.alias */, name, type: generateType(type.resolve(namespace, options)), ...this._generateDocAndMetadata(node) }; } generateVirtualClassFunction(node) { return { ...this.generateClassFunction(node), kind: "virtual_class_function" /* NodeKind.virtualClassFunction */ }; } generateNamespace(node) { function shouldGenerate(node) { return node.emit; } const { namespace, version } = node.dependency; const members = Array.from(node.members.values()) .flatMap(m => m) .filter(shouldGenerate); const classes = members .filter((m) => m instanceof IntrospectedClass) .map(m => m.asString(this)); const interfaces = members .filter((m) => m instanceof IntrospectedInterface) .map(m => m.asString(this)); const records = members .filter((m) => m instanceof IntrospectedRecord) .map(m => m.asString(this)); const constants = members .filter((m) => m instanceof IntrospectedConstant) .map(m => m.asString(this)); const callbacks = members .filter((m) => m instanceof IntrospectedCallback) .map(m => m.asString(this)); // Functions can have overrides. const functions = [ ...members .filter((m) => !(m instanceof IntrospectedCallback) && m instanceof IntrospectedFunction) .reduce((prev, next) => { if (!prev.has(next.name)) prev.set(next.name, next.asString(this)); return prev; }, new Map()) .values() ]; const errors = members .filter((m) => m instanceof IntrospectedError) .map(m => m.asString(this)); const enums = members .filter((m) => !(m instanceof IntrospectedError) && m instanceof IntrospectedEnum) .map(m => m.asString(this)); const alias = members .filter((m) => m instanceof IntrospectedAlias) .map(m => m.asString(this)); // Resolve imports after we stringify everything else, sometimes we have to ad-hoc add an import. const imports = []; return Promise.resolve({ kind: "namespace" /* NodeKind.namespace */, name: namespace, version, imports: Object.fromEntries(imports), classes, interfaces, records, constants, functions, callbacks, errors, enums, alias }); } async stringifyNamespace(node) { const { namespace } = this; this.log.debug(`Resolving the types of ${namespace.namespace}...`); try { const output = await this.generateNamespace(node); this.log.debug(`Printing ${namespace.namespace}...`); if (!output) return null; return JSON.stringify(output, null, 4); } catch (err) { this.log.error(`Failed to generate namespace: "${node.namespace}"`, err); return null; } } } //# sourceMappingURL=json.js.map