From 5a18409a6132c6dd86d0b553f637d61b73e5bddd Mon Sep 17 00:00:00 2001 From: delvedor Date: Thu, 14 Feb 2019 07:57:16 +0100 Subject: [PATCH] Added documentation generator --- scripts/run.js | 37 +++++++-- scripts/utils/generateDocs.js | 142 ++++++++++++++++++++++++++++++++++ scripts/utils/index.js | 9 ++- 3 files changed, 180 insertions(+), 8 deletions(-) create mode 100644 scripts/utils/generateDocs.js diff --git a/scripts/run.js b/scripts/run.js index 92b63fb8b..016365f2c 100644 --- a/scripts/run.js +++ b/scripts/run.js @@ -7,7 +7,13 @@ const semver = require('semver') const ora = require('ora') const rimraf = require('rimraf') const standard = require('standard') -const { generate, cloneAndCheckout, genFactory, generateRequestTypes } = require('./utils') +const { + generate, + cloneAndCheckout, + genFactory, + generateRequestTypes, + generateDocs +} = require('./utils') start(minimist(process.argv.slice(2), { string: ['tag'] @@ -23,6 +29,7 @@ function start (opts) { const apiOutputFolder = join(packageFolder, 'api') const mainOutputFile = join(packageFolder, 'index.js') const typesOutputFile = join(packageFolder, 'generated.d.ts') + const docOutputFile = join(__dirname, '..', 'docs', 'reference.asciidoc') const requestParamsOutputFile = join(packageFolder, 'requestParams.d.ts') const allSpec = [] @@ -35,8 +42,11 @@ function start (opts) { return } - readdirSync(apiFolder).forEach(generateApiFile(apiFolder, log)) - readdirSync(xPackFolder).forEach(generateApiFile(xPackFolder, log)) + const apiFolderContents = readdirSync(apiFolder) + const xPackFolderContents = readdirSync(xPackFolder) + + apiFolderContents.forEach(generateApiFile(apiFolder, log)) + xPackFolderContents.forEach(generateApiFile(xPackFolder, log)) writeFileSync( requestParamsOutputFile, @@ -55,7 +65,21 @@ function start (opts) { types, { encoding: 'utf8' } ) - lintFiles(log) + + lintFiles(log, () => { + log.text = 'Generating documentation' + const allSpec = apiFolderContents.filter(f => f !== '_common.json') + .map(f => require(join(apiFolder, f))) + .concat(xPackFolderContents.map(f => require(join(xPackFolder, f)))) + writeFileSync( + docOutputFile, + generateDocs(require(join(apiFolder, '_common.json')), allSpec), + { encoding: 'utf8' } + ) + + log.succeed('Done!') + console.log('Remember to copy the generated types into the index.d.ts file') + }) }) function generateApiFile (apiFolder, log) { @@ -77,15 +101,14 @@ function start (opts) { } } - function lintFiles (log) { + function lintFiles (log, cb) { log.text = 'Linting...' const files = [join(packageFolder, '*.js'), join(apiOutputFolder, '*.js')] standard.lintFiles(files, { fix: true }, err => { if (err) { return log.fail(err.message) } - log.succeed('Done!') - console.log('Remember to copy the generated types into the index.d.ts file') + cb() }) } } diff --git a/scripts/utils/generateDocs.js b/scripts/utils/generateDocs.js new file mode 100644 index 000000000..48df3be4a --- /dev/null +++ b/scripts/utils/generateDocs.js @@ -0,0 +1,142 @@ +'use strict' + +const dedent = require('dedent') + +function generateDocs (common, spec) { + var doc = '= API Reference\n\n' + doc += commonParameters(common) + spec.forEach(s => { + doc += '\n' + generateApiDoc(s) + }) + return doc +} + +function commonParameters (spec) { + var doc = dedent` + === Common parameters + Parameters that are accepted by all API endpoints. + https://www.elastic.co/guide/en/elasticsearch/reference/current/common-options.html + [cols=2*] + |===\n` + Object.keys(spec.params).forEach(key => { + const name = isSnakeCased(key) && key !== camelify(key) + ? '`' + key + '` or `' + camelify(key) + '`' + : '`' + key + '`' + + doc += dedent` + |${name} + |${'`' + spec.params[key].type + '`'} - ${spec.params[key].description}` + if (spec.params[key].default) { + doc += ` + + _Default:_ ${'`' + spec.params[key].default + '`'}` + } + doc += '\n\n' + }) + + doc += dedent` + |=== + ` + return doc +} + +function generateApiDoc (spec) { + const name = Object.keys(spec)[0] + const documentationUrl = spec[name].documentation + const params = [] + // url params + const urlParts = spec[name].url.parts + if (urlParts) { + Object.keys(urlParts).forEach(param => { + params.push({ + name: param, + type: getType(urlParts[param].type, urlParts[param].options), + description: urlParts[param].description, + default: urlParts[param].default + }) + }) + } + + // query params + const urlParams = spec[name].url.params + if (urlParams) { + Object.keys(urlParams).forEach(param => { + params.push({ + name: param, + type: getType(urlParams[param].type, urlParams[param].options), + description: urlParams[param].description, + default: urlParams[param].default + }) + }) + } + + // body params + const body = spec[name].body + if (body) { + params.push({ + name: 'body', + type: 'object', + description: body.description, + default: body.default + }) + } + + var doc = dedent` + === ${camelify(name)} + [source,js] + ---- + client.${camelify(name)}([params] [, options] [, callback]) + ---- + ${documentationUrl || ''} + [cols=2*] + |===` + + doc += '\n' + params.reduce((acc, val) => { + const name = isSnakeCased(val.name) && val.name !== camelify(val.name) + ? '`' + val.name + '` or `' + camelify(val.name) + '`' + : '`' + val.name + '`' + acc += dedent` + |${name} + |${'`' + val.type + '`'} - ${val.description}` + if (val.default) { + acc += ` + + _Default:_ ${'`' + val.default + '`'}` + } + return acc + '\n\n' + }, '') + + doc += dedent` + |=== + ` + return doc +} + +function getType (type, options) { + switch (type) { + case 'list': + return 'string, string[]' + case 'date': + case 'time': + case 'timeout': + return 'string' + case 'enum': + return options.map(k => `'${k}'`).join(', ') + case 'int': + case 'double': + case 'long': + return 'number' + default: + return type + } +} + +function camelify (str) { + return str[0] === '_' + ? '_' + str.slice(1).replace(/_([a-z])/g, k => k[1].toUpperCase()) + : str.replace(/_([a-z])/g, k => k[1].toUpperCase()) +} + +function isSnakeCased (str) { + return !!~str.indexOf('_') +} + +module.exports = generateDocs diff --git a/scripts/utils/index.js b/scripts/utils/index.js index 6993895f7..b76bf7586 100644 --- a/scripts/utils/index.js +++ b/scripts/utils/index.js @@ -4,5 +4,12 @@ const generate = require('./generate') const generateRequestTypes = require('./generateRequestTypes') const cloneAndCheckout = require('./clone-es') const genFactory = require('./genMain') +const generateDocs = require('./generateDocs') -module.exports = { generate, cloneAndCheckout, genFactory, generateRequestTypes } +module.exports = { + generate, + cloneAndCheckout, + genFactory, + generateRequestTypes, + generateDocs +}