Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions packages/graphql/lib/graphql-ast.explorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
OperationTypeDefinitionNode,
ScalarTypeDefinitionNode,
ScalarTypeExtensionNode,
StringValueNode,
TypeNode,
TypeSystemDefinitionNode,
TypeSystemExtensionNode,
Expand All @@ -25,6 +26,7 @@ import type {
ClassDeclarationStructure,
EnumDeclarationStructure,
InterfaceDeclarationStructure,
JSDocStructure,
MethodDeclarationStructure,
MethodSignatureStructure,
OptionalKind,
Expand Down Expand Up @@ -85,6 +87,13 @@ export interface DefinitionsGeneratorOptions {
*/
enumsAsTypes?: boolean;

/**
* If true, GraphQL descriptions are emitted as TSDoc/JSDoc comments
* on the generated types and fields.
* @default false
*/
emitDescriptions?: boolean;

/**
* If provided, specifies a function to transform type names.
* @example (name) => `${name}Schema`
Expand Down Expand Up @@ -248,6 +257,7 @@ export class GraphQLAstExplorer {
isExported: true,
isAbstract: isRoot && mode === 'class',
kind: structureKind,
docs: this.getDescriptionDocs(item, options),
properties: [],
methods: [],
};
Expand Down Expand Up @@ -338,6 +348,7 @@ export class GraphQLAstExplorer {
type: this.addSymbolIfRoot(type),
hasQuestionToken:
!required || (item as FieldDefinitionNode).arguments?.length > 0,
docs: this.getDescriptionDocs(item, options),
};
}

Expand All @@ -362,6 +373,7 @@ export class GraphQLAstExplorer {
isAbstract: mode === 'class',
name: propertyName,
returnType: `${type} | Promise<${type}>`,
docs: this.getDescriptionDocs(item, options),
parameters: this.getFunctionParameters(
(item as FieldDefinitionNode).arguments,
options,
Expand Down Expand Up @@ -476,6 +488,7 @@ export class GraphQLAstExplorer {
name: transformedName,
type: mappedTypeName ?? options.defaultScalarType ?? 'any',
isExported: true,
docs: this.getDescriptionDocs(item, options),
};
}

Expand All @@ -498,17 +511,20 @@ export class GraphQLAstExplorer {
name: transformedName,
type: values.join(' | '),
isExported: true,
docs: this.getDescriptionDocs(item, options),
};
}
const members = map(item.values, (value) => ({
name: get(value, 'name.value'),
value: get(value, 'name.value'),
docs: this.getDescriptionDocs(value, options),
}));
return {
kind: tsMorphLib.StructureKind.Enum,
name: transformedName,
members,
isExported: true,
docs: this.getDescriptionDocs(item, options),
};
}

Expand All @@ -532,6 +548,7 @@ export class GraphQLAstExplorer {
name: transformedName,
type: types.join(' | '),
isExported: true,
docs: this.getDescriptionDocs(item, options),
};
}

Expand All @@ -552,4 +569,18 @@ export class GraphQLAstExplorer {
}
return options.typeName(name);
}

private getDescriptionDocs(
item: {
readonly kind: string;
readonly description?: StringValueNode | null;
},
options: DefinitionsGeneratorOptions,
): OptionalKind<JSDocStructure>[] | undefined {
const description = get(item, 'description.value');
if (!options.emitDescriptions || !description) {
return undefined;
}
return [{ description }];
}
}
1 change: 1 addition & 0 deletions packages/graphql/lib/graphql-definitions.factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export class GraphQLDefinitionsFactory {
additionalHeader: options.additionalHeader,
defaultTypeMapping: options.defaultTypeMapping,
enumsAsTypes: options.enumsAsTypes,
emitDescriptions: options.emitDescriptions,
typeName: options.typeName,
};

Expand Down
65 changes: 65 additions & 0 deletions packages/graphql/tests/graphql-ast.explorer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,70 @@ describe('GraphQLAstExplorer', () => {
).toBe(true);
});
});

it('should not emit descriptions as TSDoc comments by default', async () => {
const astExplorer = new GraphQLAstExplorer();

const document = gql`
"""
A feline animal.
"""
type Cat {
"""
The name of the cat.
"""
name: String!
}
`;

const sourceFile = await astExplorer.explore(
document,
'/dev/null',
'interface',
{},
);

expect(sourceFile.getFullText()).not.toContain('A feline animal.');
expect(sourceFile.getFullText()).not.toContain('The name of the cat.');
});

it('should emit descriptions as TSDoc comments when "emitDescriptions" is enabled', async () => {
const astExplorer = new GraphQLAstExplorer();

const document = gql`
"""
A feline animal.
"""
type Cat {
"""
The name of the cat.
"""
name: String!
}

"""
The available colors.
"""
enum Color {
"""
The color red.
"""
RED
}
`;

const sourceFile = await astExplorer.explore(
document,
'/dev/null',
'interface',
{ emitDescriptions: true },
);
const text = sourceFile.getFullText();

expect(text).toContain('/** A feline animal. */');
expect(text).toContain('/** The name of the cat. */');
expect(text).toContain('/** The available colors. */');
expect(text).toContain('/** The color red. */');
});
});
});