graphdoc-plugin-operations
Version:
GraphQL schema HTML documentation generation, using graphdoc with Isolated Operations
112 lines (103 loc) • 4.36 kB
JavaScript
// Copyright (c) 2021 Gonzalo Müller Bravo.
// Licensed under the MIT License (MIT), see LICENSE.txt
const SchemaPlugin = require('@2fd/graphdoc/plugins/document.schema').default
const graphdocUtils = require('@2fd/graphdoc/lib/utility')
const TYPES_WITH_OPERATIONS_REGEX = /^(?:Query|Mutation)$/
function complementTypes(fromTypes, eraseByNameRegex, eraseByDescriptionRegex, assembleDescription) {
const operations = new Map()
const schemaTypes = []
for(let type of fromTypes) {
schemaTypes.push(type)
if(TYPES_WITH_OPERATIONS_REGEX.test(type.name)) {
for(let operation of type.fields) {
if (!eraseByNameRegex.test(operation.name) && !eraseByDescriptionRegex.test(operation.description)) {
const name = `${type.name}.${operation.name}`
const operationType = {
...operation,
description: assembleDescription(operation),
name,
operationName: operation.name,
parent: type,
kind: 'OPERATION',
inputFields: null,
interfaces: [],
enumValues: null,
possibleTypes: null
}
operations.set(name, operationType)
schemaTypes.push(operationType)
}
}
}
}
return {
operations,
schemaTypes
}
}
function activeOption(option) {
return option === true || option === undefined
}
function eraseRegex(from) {
return from ? new RegExp(from) : /^$/
}
class GraphdocPluginOperations {
constructor(schema, graphdocConfig, graphdocPackage) {
const coreConfig = graphdocConfig.graphdoc || {}
this.baseUrl = coreConfig.baseUrl
? coreConfig.baseUrl.endsWith('/') ? coreConfig.baseUrl.slice(0, -1) : coreConfig.baseUrl
: ''
const config = graphdocConfig['graphdoc-plugin-operations'] || {}
this.documentTitle = config.documentTitle || 'Definition'
this.navigationTitle = config.navigationTitle || 'Operations'
this.builder = new SchemaPlugin({}, {
...graphdocConfig,
graphdoc: {
...graphdocConfig.graphdoc,
baseUrl: this.baseUrl
}
}, graphdocPackage)
this.assembleDefinition = operation => graphdocUtils.html.code(this.builder.field(operation))
let assembleDescription = description => description
if (activeOption(config.extractParametersDoc)) {
this.builder.description = description => description ? `<p>${description}</p>` : ''
this.builder.argumentsDescription = () => ''
this.assembleDefinition = operation => graphdocUtils.html.code(this.builder.field(operation).replace(/<li><span class="tab"><\/span><\/li>/g, ''))
const parametersTitle = config.parametersTitle !== '' ? `<p>${ config.parametersTitle || 'Parameters:'}</p><br/>` : ''
assembleDescription = operation => operation.args && operation.args.length !== 0
? `${operation.description ? `<p>${operation.description}</p><br/>` : ''}${parametersTitle}${operation.args.map(param => this.builder.argumentDescription(param)).join('')}`
: operation.description
}
const complemented = complementTypes(
schema.types || [],
eraseRegex(config.eraseByNameRegex),
eraseRegex(config.eraseByDescriptionRegex),
assembleDescription
)
this.operations = complemented.operations
this.operationsNames = Array.from(this.operations.keys()).sort((a, b) => a > b ? 1 : -1)
schema.types = complemented.schemaTypes
if (activeOption(config.enableAssets)) {
this.getHeaders = this.builder.getHeaders
this.getAssets = this.builder.getAssets
}
}
getDocuments(buildForType) {
const type = this.operations.get(buildForType)
return type
? [ new graphdocUtils.DocumentSection(this.documentTitle, this.assembleDefinition({
...type,
name: type.operationName,
description: ''
})) ]
: []
}
getNavigations(buildForType) {
const currentOperationsSection = []
for (let operation of this.operationsNames) {
currentOperationsSection.push(new graphdocUtils.NavigationItem(operation, `${this.baseUrl}/${graphdocUtils.getFilenameOf({ name: operation })}`, operation === buildForType))
}
return [ new graphdocUtils.NavigationSection(this.navigationTitle, currentOperationsSection) ]
}
}
module.exports.default = GraphdocPluginOperations