import marked from 'marked'
const schema = require('../schema.json').data.__schema
// Ideally, we could just spit out the existing description Markdown everywhere
// and leave it to be rendered by whatever processes the output. But some
// Markdown renderers, including GitHub's, don't process Markdown if it's within
// an HTML tag. So in some places (like descriptions of the types themselves) we
// just output the raw description. In other places, like table cells, we need
// to output pre-rendered Markdown, otherwise GitHub won't interpret it.
marked.setOptions({
breaks: false
})
function markdown (markup) {
return marked(markup || '')
.replace(/<\/p>\s*
/g, '
')
.replace(/<\/?p>/g, '')
.trim()
}
function sortBy (arr, property) {
arr.sort((a, b) => {
const aValue = a[property]
const bValue = b[property]
if (aValue > bValue) return 1
if (bValue > aValue) return -1
return 0
})
}
function renderType (type) {
if (type.kind === 'NON_NULL') {
return renderType(type.ofType) + '!'
}
if (type.kind === 'LIST') {
return `[${renderType(type.ofType)}]`
}
return `[${type.name}](#${type.name.toLowerCase()})`
}
function renderObject (type, { skipTitle = false } = {}) {
if (!skipTitle) {
console.log(`\n### ${type.name}\n`)
}
if (type.description) {
console.log(`${type.description}\n`)
}
console.log('
')
console.log(' | Field / Argument | ')
console.log(' Type | ')
console.log(' Description | ')
console.log('')
type.fields.forEach(field => {
console.log(' ')
console.log(` | ${field.name} | `)
console.log(` ${markdown(renderType(field.type))} | `)
console.log(` ${markdown(field.description)} | `)
console.log('
')
if (field.args.length) {
field.args.forEach((arg, i) => {
console.log(' ')
console.log(` | ${arg.name} | `)
console.log(` ${markdown(renderType(arg.type))} | `)
console.log(` ${markdown(arg.description)} | `)
console.log('
')
})
}
})
console.log('
')
}
const types = schema.types.filter(type => !type.name.startsWith('__'))
const query = types.filter(type => type.name === schema.queryType.name)[0]
const objects = types.filter(type => type.kind === 'OBJECT' && type !== query)
const enums = types.filter(type => type.kind === 'ENUM').sort()
const scalars = types.filter(type => type.kind === 'SCALAR').sort()
const interfaces = types.filter(type => type.kind === 'INTERFACE').sort()
sortBy(objects, 'name')
sortBy(enums, 'name')
sortBy(scalars, 'name')
sortBy(interfaces, 'name')
console.log('# Schema Types\n')
console.log('You may also be interested in the [schema in GraphQL syntax](schema.md).\n')
console.log('**Table of Contents**
')
console.log(' - [Query](#query)
')
console.log(' - [Objects](#objects)
')
objects.forEach(type => {
console.log(` - [${type.name}](#${type.name.toLowerCase()})
`)
})
console.log('
')
console.log(' - [Enums](#enums)
')
enums.forEach(type => {
console.log(` - [${type.name}](#${type.name.toLowerCase()})
`)
})
console.log('
')
console.log(' - [Scalars](#scalars)
')
scalars.forEach(type => {
console.log(` - [${type.name}](#${type.name.toLowerCase()})
`)
})
console.log('
')
console.log(' - [Interfaces](#interfaces)
')
interfaces.forEach(type => {
console.log(` - [${type.name}](#${type.name.toLowerCase()})
`)
})
console.log('
')
console.log('
')
console.log(`\n## Query ${query.name === 'Query' ? '' : '(' + query.name + ')'}`)
renderObject(query, { skipTitle: true })
console.log('\n## Objects')
objects.forEach(type => renderObject(type))
console.log('\n## Enums')
enums.forEach(type => {
console.log(`\n### ${type.name}\n`)
if (type.description) {
console.log(`${type.description}\n`)
}
console.log('')
console.log(' | Value | ')
console.log(' Description | ')
console.log('')
type.enumValues.forEach(value => {
console.log(' ')
console.log(` | ${value.name} | `)
console.log(` ${markdown(value.description)} | `)
console.log('
')
})
console.log('
')
})
console.log('\n## Scalars\n')
scalars.forEach(type => {
console.log(`### ${type.name}\n`)
if (type.description) {
console.log(`${type.description}\n`)
}
})
console.log('\n## Interfaces\n')
interfaces.forEach(type => renderObject(type))