diff --git a/packages/snaps-rpc-methods/scripts/generate-schema.mts b/packages/snaps-rpc-methods/scripts/generate-schema.mts index dd0c147c40..1ed18b5f2a 100644 --- a/packages/snaps-rpc-methods/scripts/generate-schema.mts +++ b/packages/snaps-rpc-methods/scripts/generate-schema.mts @@ -11,6 +11,7 @@ import type { PropertyAssignment, Symbol, Type, + TypeAliasDeclaration, TypeNode, VariableDeclaration, } from 'ts-morph'; @@ -423,6 +424,57 @@ function getTypeAliasDeclaration(type: Type) { return declaration?.asKind(SyntaxKind.TypeAliasDeclaration) ?? null; } +/** + * Unwrap an `InferMatching` type node to get the underlying type, if the given + * type node is an `InferMatching` type. This is needed to get the correct + * description for certain types that are defined using `InferMatching`, such + * as `DialogParams`, since the JSDoc comments are on the underlying type rather + * than the `InferMatching` type itself. If the given declaration is not an + * `InferMatching` type, it is returned as-is. + * + * @param declaration - The type alias declaration that may be an + * `InferMatching` type. + * @returns The underlying type alias declaration if the given declaration is an + * `InferMatching` type, or the given declaration otherwise. + */ +function unwrapInferMatchingTypeNode(declaration: TypeAliasDeclaration) { + const typeNode = declaration.getTypeNodeOrThrow(); + if (!typeNode.isKind(SyntaxKind.TypeReference)) { + return declaration; + } + + const typeReference = typeNode.asKindOrThrow(SyntaxKind.TypeReference); + if (typeReference.getTypeName().getText() !== 'InferMatching') { + return declaration; + } + + const typeArguments = typeReference.getTypeArguments(); + assert( + typeArguments.length === 2, + 'Expected `InferMatching` to have exactly two type arguments.', + ); + + const underlyingTypeNode = typeArguments[1]; + const symbol = underlyingTypeNode + .asKindOrThrow(SyntaxKind.TypeReference) + .getTypeName() + .getSymbolOrThrow() + .getAliasedSymbolOrThrow(); + + const underlyingDeclaration = symbol + .getDeclarations() + .find((symbolDeclaration): symbolDeclaration is TypeAliasDeclaration => + symbolDeclaration.isKind(SyntaxKind.TypeAliasDeclaration), + ); + + assert( + underlyingDeclaration, + 'Expected declaration of underlying type not found.', + ); + + return underlyingDeclaration; +} + /** * Get the description of a type node from its JSDoc comments, if it has any. * @@ -436,14 +488,15 @@ function getTypeNodeDescription(typeNode: TypeNode) { .getTypeName() .asKindOrThrow(SyntaxKind.Identifier); - const symbol = identifier.getSymbol()?.getAliasedSymbol(); + const symbol = + identifier.getSymbol()?.getAliasedSymbol() ?? identifier.getSymbol(); if (!symbol) { return null; } const declaration = symbol .getDeclarations() - .find((symbolDeclarations) => + .find((symbolDeclarations): symbolDeclarations is TypeAliasDeclaration => symbolDeclarations.isKind(SyntaxKind.TypeAliasDeclaration), ); @@ -451,7 +504,8 @@ function getTypeNodeDescription(typeNode: TypeNode) { return null; } - const jsDocs = declaration + const unwrappedDeclaration = unwrapInferMatchingTypeNode(declaration); + const jsDocs = unwrappedDeclaration .asKindOrThrow(SyntaxKind.TypeAliasDeclaration) .getJsDocs();