graphqldoc
Version:
Generate GraphQL docs from schema.
289 lines (288 loc) • 12 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = require("path");
const wrap = require("word-wrap");
const utility_1 = require("../../lib/utility");
const MAX_CODE_LEN = 80;
// const MAX_COMMENT_LEN = 80;
class SchemaPlugin extends utility_1.Plugin {
getHeaders() {
return [
'<link href="https://fonts.googleapis.com/css?family=Ubuntu+Mono:400,700" rel="stylesheet">',
'<link type="text/css" rel="stylesheet" href="./assets/code.css" />',
'<script src="./assets/line-link.js"></script>'
];
}
getAssets() {
return [
path_1.resolve(__dirname, 'assets/code.css'),
path_1.resolve(__dirname, 'assets/line-link.js')
];
}
getDocuments(buildForType) {
this.html = new utility_1.HTML();
const code = this.code(buildForType);
if (code)
return [
new utility_1.DocumentSection('GraphQL Schema definition', this.html.code(code))
];
return [];
}
code(buildForType) {
if (!buildForType)
return this.schema(this.document);
const directive = this.document
.directives
.find((directive) => directive.name === buildForType);
if (directive)
return this.directive(directive);
const type = this.document
.types
.find((type) => type.name === buildForType);
if (type) {
switch (type.kind) {
case utility_1.SCALAR:
return this.scalar(type);
case utility_1.OBJECT:
return this.object(type);
case utility_1.INTERFACE:
return this.interfaces(type);
case utility_1.UNION:
return this.union(type);
case utility_1.ENUM:
return this.enum(type);
case utility_1.INPUT_OBJECT:
return this.inputObject(type);
}
}
throw new TypeError('Unexpected type: ' + buildForType);
}
argument(arg) {
return this.html.property(arg.name) + ': ' +
this.html.useIdentifier(arg.type, this.url(arg.type)) // + ' ' + this.deprecated(arg);
;
}
argumentLength(arg) {
return arg.name.length + 1 + this.html.useIdentifierLength(arg.type);
}
arguments(fieldOrDirectives) {
if (fieldOrDirectives.args.length === 0) {
return '';
}
return '(' +
fieldOrDirectives.args
.map((arg) => this.argument(arg))
.join(', ') +
')';
}
argumentsLength(fieldOrDirectives) {
if (fieldOrDirectives.args.length === 0) {
return 0;
}
return fieldOrDirectives.args.reduce((sum, arg) => sum + this.argumentLength(arg), 2);
}
argumentsMultiline(fieldOrDirectives) {
if (fieldOrDirectives.args.length === 0) {
return [];
}
const maxIndex = fieldOrDirectives.args.length - 1;
return fieldOrDirectives.args
.map((arg, index) => {
return index < maxIndex ?
this.argument(arg) + ',' :
this.argument(arg);
});
}
argumentDescription(arg) {
const desc = !arg.description ?
'[' + this.html.highlight('Not documented') + ']' : arg.description;
return this.description(this.html.highlight(arg.name) + ': ' + desc);
}
argumentsDescription(fieldOrDirectives) {
const argsWithDescriptions = fieldOrDirectives.args.filter(arg => arg.description);
if (argsWithDescriptions.length === 0) {
return [];
}
const reduceArguments = (descriptions, arg) => descriptions.concat(this.argumentDescription(arg));
return argsWithDescriptions
.reduce(reduceArguments, [this.html.comment('Arguments')]);
}
deprecated(fieldOrEnumVal) {
if (!fieldOrEnumVal.isDeprecated)
return '';
if (!fieldOrEnumVal.deprecationReason) {
return this.html.keyword('@deprecated');
}
return this.html.keyword('@deprecated') +
'( reason: ' + this.html.value('"' + fieldOrEnumVal.deprecationReason + '" ') + ' )';
}
deprecatedLength(fieldOrEnumVal) {
if (!fieldOrEnumVal.isDeprecated)
return 0;
if (!fieldOrEnumVal.deprecationReason) {
return '@deprecated'.length;
}
return '@deprecated( reason: "'.length + fieldOrEnumVal.deprecationReason.length + '" )'.length;
}
description(description) {
if (description)
return wrap(description, {
width: MAX_CODE_LEN
})
.split('\n')
.map(l => this.html.comment(l));
return [];
}
directive(directive) {
return this.html.line(this.html.keyword('directive') + ' ' +
this.html.keyword('@' + directive.name) + this.arguments(directive) + ' on ' +
directive.locations.map(location => this.html.keyword(location)).join(' | '));
}
enum(type) {
const reduceEnumValues = (lines, enumValue) => lines
.concat([''], this.description(enumValue.description), [this.html.property(enumValue.name) + this.deprecated(enumValue)]);
return this.html.line(this.html.keyword('enum') + ' ' + this.html.identifier(type) + ' {') +
type.enumValues
.reduce(reduceEnumValues, [])
.map(line => this.html.line(this.html.tab(line)))
.join('') +
this.html.line('}');
}
field(field) {
const fieldDescription = this.description(field.description);
const argumentsDescription = this.argumentsDescription(field);
if (fieldDescription.length > 0 && argumentsDescription.length)
fieldDescription.push(this.html.comment(''));
const fieldDefinition = field.args.length > 0 && this.fieldLength(field) > MAX_CODE_LEN ?
// Multiline definition:
// fieldName(
// argumentName: ArgumentType, \n ...
// ): ReturnType [@deprecated...]
[
this.html.property(field.name) + '(',
...this.argumentsMultiline(field).map(l => this.html.tab(l)),
'): ' + this.html.useIdentifier(field.type, this.url(field.type)) + ' ' + this.deprecated(field)
] :
// Single line
// fieldName(argumentName: ArgumentType): ReturnType [@deprecated...]
[
this.html.property(field.name) + this.arguments(field) + ': ' +
this.html.useIdentifier(field.type, this.url(field.type)) + ' ' + this.deprecated(field)
];
return []
.concat(fieldDescription)
.concat(argumentsDescription)
.concat(fieldDefinition)
.map(line => this.html.line(this.html.tab(line)))
.join('');
}
fieldLength(field) {
return field.name.length + this.argumentsLength(field) +
': '.length + this.html.useIdentifierLength(field) + ' '.length +
this.deprecatedLength(field);
}
fields(type) {
let fields = '';
fields += this.html.line();
for (let i = 0; i < type.fields.length; i++) {
fields += this.field(type.fields[i]);
fields += this.html.line();
}
return fields;
}
inputObject(type) {
return this.html.line(this.html.keyword('input') + ' ' + this.html.identifier(type) + ' {') +
this.inputValues(type.inputFields) +
this.html.line('}');
}
inputValues(inputValues) {
return inputValues
.map(inputValue => this.html.line(this.html.tab(this.inputValue(inputValue))))
.join('');
}
inputValue(arg) {
const argDescription = this.description(arg.description);
return []
.concat(argDescription)
.concat([
this.html.property(arg.name) + ': ' +
this.html.useIdentifier(arg.type, this.url(arg.type)) // + ' ' + this.deprecated(arg)
])
.map(line => this.html.line(this.html.tab(line)))
.join('');
}
interfaces(type) {
return this.html.line(this.html.keyword('interface') + ' ' + this.html.identifier(type) + ' {') +
this.fields(type) +
this.html.line('}');
}
object(type) {
const interfaces = type.interfaces
.map(i => this.html.useIdentifier(i, this.url(i)))
.join(', ');
const implement = interfaces.length === 0 ? '' :
' ' + this.html.keyword('implements') + ' ' + interfaces;
return this.html.line(this.html.keyword('type') + ' ' + this.html.identifier(type) + implement + ' {') +
this.fields(type) +
this.html.line('}');
}
scalar(type) {
return this.html.line(this.html.keyword('scalar') + ' ' + this.html.identifier(type));
}
schema(schema) {
let definition = this.html.line(this.html.keyword('schema') + ' {');
if (schema.queryType)
definition += this.html.line() +
this.description(schema.queryType.description)
.map(line => this.html.line(this.html.tab(line)))
.join('') +
this.html.line(this.html.tab(this.html.property('query') + ': ' + this.html.useIdentifier(schema.queryType, this.url(schema.queryType))));
if (schema.mutationType)
definition += this.html.line() +
this.description(schema.mutationType.description)
.map(line => this.html.line(this.html.tab(line)))
.join('') +
this.html.line(this.html.tab(this.html.property('mutation') + ': ' + this.html.useIdentifier(schema.mutationType, this.url(schema.mutationType))));
if (schema.subscriptionType)
definition += this.html.line() +
this.description(schema.subscriptionType.description)
.map(line => this.html.line(this.html.tab(line)))
.join('') +
this.html.line(this.html.tab(this.html.property('subscription') + ': ' + this.html.useIdentifier(schema.subscriptionType, this.url(schema.subscriptionType))));
definition += this.html.line('}');
return definition;
/* .concat(
schema.directives
.map((directive) => {
return this.html.line(this.html.comment('DIRECTIVE')) +
this.description(directive.description)
.map(line => this.html.line(line))
.join('') +
this.code(directive.name);
}),
schema.types
.sort((a: SchemaType, b: SchemaType) => {
return order[a.kind].localeCompare(order[b.kind]);
})
.map((type) => {
return this.html.line(this.html.comment(type.kind)) +
this.description(type.description)
.map(line => this.html.line(line))
.join('') +
this.code(type.name);
}))*/
/* return [this.schemaDefinition(schema)]
.concat(
directives.map(directive => this.directive(directive)),
types.map((type) => this.type(type) as string)
)
.join('\n\n') + '\n';*/
}
union(type) {
return this.html.line(this.html.keyword('union') + ' ' + this.html.identifier(type) + ' = ' +
type.possibleTypes
.map(type => this.html.useIdentifier(type, this.url(type)))
.join(' | '));
}
}
exports.default = SchemaPlugin;