UNPKG

@ts-for-gir/lib

Version:

Typescript .d.ts generator from GIR for gjs

140 lines (121 loc) 5.12 kB
import { IntrospectedConstructor } from "../../gir/constructor.ts"; import type { IntrospectedFunction } from "../../gir/function.ts"; import type { IntrospectedClassFunction } from "../../gir/introspected-classes.ts"; import type { IntrospectedNamespace } from "../../gir/namespace.ts"; import type { IntrospectedFunctionParameter } from "../../gir/parameter.ts"; import type { TypeIdentifier } from "../../gir.ts"; import { isSubtypeOf } from "../type-resolution.ts"; /** * Checks if two functions are conflicting based on their signatures */ export function isConflictingFunction( namespace: IntrospectedNamespace, childThis: TypeIdentifier, child: IntrospectedFunction | IntrospectedClassFunction | IntrospectedConstructor, parentThis: TypeIdentifier, parent: IntrospectedClassFunction | IntrospectedFunction | IntrospectedConstructor, ): boolean { if (!parent.isIntrospectable || !child.isIntrospectable) { return false; } // Handle constructor conflicts if (isConstructorConflict(namespace, childThis, child, parentThis, parent)) { return true; } // Handle mixed constructor/function conflicts if (isMixedConstructorFunctionConflict(child, parent)) { return true; } // Handle different function types (no conflict if different prototypes) if (hasDifferentPrototypes(child, parent)) { return false; } // Check parameter and return type conflicts return hasParameterOrReturnTypeConflicts(namespace, childThis, child, parentThis, parent); } function isConstructorConflict( namespace: IntrospectedNamespace, childThis: TypeIdentifier, child: IntrospectedFunction | IntrospectedClassFunction | IntrospectedConstructor, parentThis: TypeIdentifier, parent: IntrospectedClassFunction | IntrospectedFunction | IntrospectedConstructor, ): boolean { if (!(child instanceof IntrospectedConstructor && parent instanceof IntrospectedConstructor)) { return false; } return ( child.parameters.length > parent.parameters.length || !isSubtypeOf(namespace, childThis, parentThis, child.return(), parent.return()) || child.parameters.some((p, i) => !isSubtypeOf(namespace, childThis, parentThis, p.type, parent.parameters[i].type)) ); } function isMixedConstructorFunctionConflict( child: IntrospectedFunction | IntrospectedClassFunction | IntrospectedConstructor, parent: IntrospectedClassFunction | IntrospectedFunction | IntrospectedConstructor, ): boolean { return child instanceof IntrospectedConstructor !== parent instanceof IntrospectedConstructor; } function hasDifferentPrototypes( child: IntrospectedFunction | IntrospectedClassFunction | IntrospectedConstructor, parent: IntrospectedClassFunction | IntrospectedFunction | IntrospectedConstructor, ): boolean { // This occurs if two functions of the same name are passed but they // are different types (e.g. GirStaticClassFunction vs GirClassFunction) return Object.getPrototypeOf(child) !== Object.getPrototypeOf(parent); } function hasParameterOrReturnTypeConflicts( namespace: IntrospectedNamespace, childThis: TypeIdentifier, child: IntrospectedFunction | IntrospectedClassFunction | IntrospectedConstructor, parentThis: TypeIdentifier, parent: IntrospectedClassFunction | IntrospectedFunction | IntrospectedConstructor, ): boolean { // Check basic parameter conflicts if (child.parameters.length > parent.parameters.length) { return true; } // Check return type conflicts if (!isSubtypeOf(namespace, childThis, parentThis, child.return(), parent.return())) { return true; } // Check parameter type conflicts if (hasParameterTypeConflicts(namespace, childThis, child.parameters, parentThis, parent.parameters)) { return true; } // Check output parameter conflicts if both functions support them return hasOutputParameterConflicts(namespace, childThis, child, parentThis, parent); } function hasParameterTypeConflicts( namespace: IntrospectedNamespace, childThis: TypeIdentifier, childParams: IntrospectedFunctionParameter[], parentThis: TypeIdentifier, parentParams: IntrospectedFunctionParameter[], ): boolean { return childParams.some( (childParam, i) => !isSubtypeOf(namespace, childThis, parentThis, childParam.type, parentParams[i].type), ); } function hasOutputParameterConflicts( namespace: IntrospectedNamespace, childThis: TypeIdentifier, child: IntrospectedFunction | IntrospectedClassFunction | IntrospectedConstructor, parentThis: TypeIdentifier, parent: IntrospectedClassFunction | IntrospectedFunction | IntrospectedConstructor, ): boolean { // Only check output parameters if both functions have them (constructors don't have output_parameters) const childHasOutputParams = "output_parameters" in child; const parentHasOutputParams = "output_parameters" in parent; if (!childHasOutputParams || !parentHasOutputParams) { return false; } // Length mismatch if (child.output_parameters.length !== parent.output_parameters.length) { return true; } // Type mismatch return child.output_parameters.some( (childParam, i) => !isSubtypeOf(namespace, childThis, parentThis, childParam.type, parent.output_parameters[i].type), ); }