@graphql-codegen/jsdoc
Version:
GraphQL Code Generator plugin for generating JSDoc based types for GraphQL queries, mutations, subscriptions and fragments
197 lines (196 loc) • 7.21 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.plugin = void 0;
const graphql_1 = require("graphql");
const plugin_helpers_1 = require("@graphql-codegen/plugin-helpers");
const visitor_plugin_common_1 = require("@graphql-codegen/visitor-plugin-common");
const transformScalar = (scalar) => {
if (visitor_plugin_common_1.DEFAULT_SCALARS[scalar] === undefined) {
return scalar;
}
return visitor_plugin_common_1.DEFAULT_SCALARS[scalar];
};
const createDocBlock = (lines) => {
const typedef = [
'/**',
...lines
.filter(t => t && t !== '')
.reduce((prev, t) => [...prev, ...t.split('\n')], [])
.map(line => ` * ${line}`),
' */',
];
const block = typedef.join('\n');
return block;
};
const createDescriptionBlock = (nodeWithDesc) => {
var _a;
if ((_a = nodeWithDesc === null || nodeWithDesc === void 0 ? void 0 : nodeWithDesc.description) === null || _a === void 0 ? void 0 : _a.value) {
return nodeWithDesc.description.value;
}
return '';
};
const plugin = (schema, documents) => {
const parsedSchema = (0, plugin_helpers_1.getCachedDocumentNodeFromSchema)(schema);
const mappedDocuments = documents
.map(document => document.document)
.filter(document => document !== undefined);
const ast = (0, graphql_1.concatAST)([parsedSchema, ...mappedDocuments]);
const schemaTypes = (0, graphql_1.visit)(ast, {
Document: {
leave(node) {
return node.definitions;
},
},
SchemaDefinition: {
leave: () => null,
},
ObjectTypeDefinition: {
leave(node) {
const typedNode = node;
return createDocBlock([
createDescriptionBlock(node),
`@typedef {Object} ${typedNode.name}`,
...typedNode.fields,
]);
},
},
InputObjectTypeDefinition: {
leave(node) {
const typedNode = node;
return createDocBlock([
createDescriptionBlock(node),
`@typedef {Object} ${typedNode.name}`,
...typedNode.fields,
]);
},
},
InterfaceTypeDefinition: {
leave(node) {
const typedNode = node;
return createDocBlock([
createDescriptionBlock(node),
`@typedef {Object} ${typedNode.name}`,
...typedNode.fields,
]);
},
},
UnionTypeDefinition: {
leave(node) {
if (node.types !== undefined) {
return createDocBlock([
createDescriptionBlock(node),
`@typedef {(${node.types.join('|')})} ${node.name}`,
]);
}
return node;
},
},
Name: {
leave(node) {
return node.value;
},
},
NamedType: {
leave(node) {
return transformScalar(node.name);
},
},
NonNullType: {
leave(node, _, parent) {
if (parent === undefined) {
return node;
}
return node.type;
},
},
Directive: {
enter(node) {
var _a;
if (node.name.value !== 'deprecated') {
return null;
}
const reason = (_a = node.arguments) === null || _a === void 0 ? void 0 : _a.find(arg => arg.name.value === 'reason');
if ((reason === null || reason === void 0 ? void 0 : reason.value.kind) !== 'StringValue') {
return null;
}
return ` - DEPRECATED: ${reason.value.value}`;
},
},
DirectiveDefinition: {
enter() {
/** This plugin currently does not support unused Directives. */
return null;
},
},
FieldDefinition: {
enter(node) {
if (node.type.kind === 'NonNullType') {
return { ...node, nonNullable: true };
}
return node;
},
leave(node) {
var _a;
const fieldName = node.nonNullable ? node.name : `[${node.name}]`;
const description = node.description && node.description.value ? ` - ${node.description.value}` : '';
const directives = (_a = node === null || node === void 0 ? void 0 : node.directives) === null || _a === void 0 ? void 0 : _a.filter(d => d !== null && d !== undefined);
return `@property {${node.type}} ${fieldName}${description}${directives}`;
},
},
InputValueDefinition: {
enter(node) {
if (node.type.kind === 'NonNullType') {
return { ...node, nonNullable: true };
}
return node;
},
leave(node) {
const fieldName = node.nonNullable ? node.name : `[${node.name}]`;
return `@property {${node.type}} ${fieldName}${node.description && node.description.value ? ` - ${node.description.value}` : ''}`;
},
},
ListType: {
enter(node) {
if (node.type.kind === 'NonNullType') {
return { ...node, nonNullItems: true };
}
return node;
},
leave(node) {
const type = node.nonNullItems ? node.type : `(${node.type}|null|undefined)`;
return `Array<${type}>`;
},
},
ScalarTypeDefinition: {
leave(node) {
return createDocBlock([createDescriptionBlock(node), `@typedef {*} ${node.name}`]);
},
},
EnumTypeDefinition: {
leave(node) {
var _a;
const values = (_a = node === null || node === void 0 ? void 0 : node.values) === null || _a === void 0 ? void 0 : _a.map(value => `"${value.name}"`).join('|');
/** If for some reason the enum does not contain any values we fallback to "any" or "*" */
const valueType = values ? `(${values})` : '*';
return createDocBlock([
createDescriptionBlock(node),
`@typedef {${valueType}} ${node.name}`,
]);
},
},
OperationDefinition: {
enter() {
/** This plugin currently does not support operations yet. */
return null;
},
},
FragmentDefinition: {
enter() {
/** This plugin currently does not support fragments yet. */
return null;
},
},
});
return schemaTypes.join('\n\n');
};
exports.plugin = plugin;
;