diff --git a/README.md b/README.md index 9f011518..a2365ba6 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ node widdershins --search false --language_tabs 'ruby:Ruby' 'python:Python' --su | --omitHeader | options.omitHeader | `boolean` | `false` | Omit the header / YAML front-matter in the generated Markdown file. | | --resolve | options.resolve | `boolean` | `false` | Resolve external $refs, using the `source` parameter or the input file as the base location. | | --shallowSchemas | options.shallowSchemas | `boolean` | `false` | When referring to a schema with a $ref, don't show the full contents of the schema. | +| --loadMdPrefix | options.loadMdPrefix | `string` | `x-md-`| Prefix of OpenAPI extension that indicates MD files paths to load and can be injected anywhere in the output MD | N/A | options.source | `string` | None | The absolute location or URL of the source file to use as the base to resolve relative references ($refs) from; required if options.resolve is set to true. For CLI commands, Widdershins uses the input file as the base for the $refs. | | --summary | options.tocSummary | `boolean` | `false` | Use the operation summary as the TOC entry instead of the ID. | | --useBodyName | options.useBodyName | `boolean` | Use original param name for OpenAPI 2.0 body parameter. | diff --git a/lib/common.js b/lib/common.js index 25173a18..e3f77074 100644 --- a/lib/common.js +++ b/lib/common.js @@ -1,7 +1,6 @@ 'use strict'; const fs = require('fs'); - const jptr = require('reftools/lib/jptr.js').jptr; const sampler = require('openapi-sampler'); const safejson = require('fast-safe-stringify'); @@ -526,6 +525,21 @@ function html(markdown,header,options) { return preface+md.render(markdown); } +function loadMD(sourceSection, destSection, mdFieldPrefix) { + for (let field in sourceSection) { + if (field.startsWith(mdFieldPrefix)) { + //Replacing '-' so that field can be used in dot templates + let newFieldName = field.split("-").join("_"); + try { + destSection[newFieldName] = md.render(fs.readFileSync(sourceSection[field],'utf8')); + } + catch (ex) { + console.log(ex.message); + } + } + } +} + module.exports = { statusCodes : statusCodes, doContentType : doContentType, @@ -541,6 +555,7 @@ module.exports = { schemaToArray : schemaToArray, removeDupeBlankLines: removeDupeBlankLines, toPrimitive: toPrimitive, - html : html + html : html, + loadMD: loadMD }; diff --git a/lib/openapi3.js b/lib/openapi3.js index 343ee9ea..e53290b1 100644 --- a/lib/openapi3.js +++ b/lib/openapi3.js @@ -21,6 +21,7 @@ const swagger2openapi = require('swagger2openapi'); const common = require('./common.js'); let templates; +let loadMdPrefix; function convertToToc(source, data) { let resources = {}; @@ -28,6 +29,8 @@ function convertToToc(source, data) { if (source.tags) { for (let tag of source.tags) { resources[tag.name] = { count: 0, methods: {}, description: tag.description, externalDocs: tag.externalDocs }; + //Load MD for tags + common.loadMD(tag, resources[tag.name], loadMdPrefix); } } for (var p in source.paths) { @@ -36,6 +39,8 @@ function convertToToc(source, data) { if ((m !== 'parameters') && (m !== 'summary') && (m !== 'description') && (!m.startsWith('x-'))) { var method = {}; method.operation = source.paths[p][m]; + ///load operation level MD + common.loadMD(method.operation, method.operation, loadMdPrefix); method.pathItem = source.paths[p]; method.verb = m; method.path = p; @@ -57,6 +62,8 @@ function convertToToc(source, data) { } resources[tagName].count++; resources[tagName].methods[sMethodUniqueName] = method; + //load MD for paths + common.loadMD(source.paths[p], resources[tagName], loadMdPrefix); } } } @@ -275,9 +282,11 @@ function getParameters(data) { for (let ess of effSecurity) { if (data.api.components.securitySchemes[ess]) { let secScheme = data.api.components.securitySchemes[ess]; + let authHeader = {}; + //load Security Scheme level MD + common.loadMD(secScheme, authHeader, loadMdPrefix); if (!existingAuth && ((secScheme.type === 'oauth2') || (secScheme.type === 'openIdConnect') || ((secScheme.type === 'http') && (secScheme.scheme === 'bearer')))) { - let authHeader = {}; authHeader.name = 'Authorization'; authHeader.type = 'string'; authHeader.in = 'header'; @@ -288,7 +297,6 @@ function getParameters(data) { data.allHeaders.push(authHeader); } else if ((secScheme.type === 'apiKey') && (secScheme.in === 'header')) { - let authHeader = {}; authHeader.name = secScheme.name; authHeader.type = 'string'; authHeader.in = 'header'; @@ -456,6 +464,8 @@ function getResponses(data) { } entry.content = response.content; entry.links = response.links; + //load response level MD + common.loadMD(response, entry, loadMdPrefix); responses.push(entry); } } @@ -615,10 +625,10 @@ function convertInner(api, options) { defaults.theme = 'darkula'; defaults.headings = 2; defaults.templateCallback = function (template, stage, data) { return data; }; + defaults.loadMdPrefix = 'x-md-'; defaults.sample = true; - options = Object.assign({}, defaults, options); - + loadMdPrefix = options.loadMdPrefix; let data = {}; if (options.verbose) console.warn('starting deref', api.info.title); if (api.components) { @@ -633,6 +643,8 @@ function convertInner(api, options) { if (data.api.components && data.api.components.schemas && data.api.components.schemas["x-widdershins-oldRef"]) { delete data.api.components.schemas["x-widdershins-oldRef"]; } + //Load root level MD + common.loadMD(api, data, loadMdPrefix); if (typeof templates === 'undefined') { templates = dot.process({ path: path.join(__dirname, '..', 'templates', 'openapi3') }); diff --git a/widdershins.js b/widdershins.js index b967d4e6..db6dad20 100755 --- a/widdershins.js +++ b/widdershins.js @@ -47,6 +47,9 @@ var argv = require('yargs') .describe('lang','Generate the list of languages for code samples based on the languages used in the source file\'s `x-code-samples` examples.') .array('language_tabs') .describe('language_tabs', 'List of language tabs for code samples using "language[:label[:client]]" format, such as `javascript:JavaScript:request`.') + .string('loadMdPrefix') + .describe('loadMdPrefix', 'Prefix of OpenAPI extension that indicates MD files paths to load and can be injected anywhere in the output MD') + .default('loadMdPrefix', 'x-md') .number('maxLevel') .alias('m','maxDepth') .describe('maxDepth','Maximum depth to show for schema examples.') @@ -166,6 +169,7 @@ options.customApiKeyValue = argv.customApiKeyValue; options.html = argv.html; options.respec = argv.respec; options.useBodyName = argv.useBodyName; +options.loadMdPrefix = argv.loadMdPrefix; if (argv.search === false) options.search = false; if (argv.includes) options.includes = argv.includes.split(','); if (argv.respec) {