Skip to content

Commit

Permalink
repo renamed from openapi2md
Browse files Browse the repository at this point in the history
  • Loading branch information
carlosrivera committed Mar 2, 2021
1 parent 8ac543e commit 0044e6c
Show file tree
Hide file tree
Showing 9 changed files with 299 additions and 30 deletions.
12 changes: 7 additions & 5 deletions example/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@ const convert = require('../dist').default;
const bundler = require('../dist/bundler').default;
const OpenAPISampler = require('openapi-sampler');

bundler('../example/petstore.json', './')
console.log(process.cwd())
/*
bundler('example/petstore.json', './')
.then(spec => {
console.log(OpenAPISampler.sample(spec.components.schemas.Pet, {}, spec));
//console.log(OpenAPISampler.sample(spec.components.schemas.Pet, {}, spec));
})
.catch(err => {
console.error(err);
})
})*/

convert('../example/petstore.json', './build')
convert('example/petstore.json', { outPath: './build', snippetTargets: ["node", "python"] })
.then(() => {
console.log("Finihsed.")
console.log("Finished.")
})
.catch(err => {
console.error(err);
Expand Down
2 changes: 1 addition & 1 deletion example/petstore.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
},
"servers": [
{
"url": "/api/v3"
"url": "http://swagger.io/api/v3"
}
],
"tags": [
Expand Down
15 changes: 9 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@synx-ai/openapi2md",
"version": "0.2.4",
"name": "@synx-ai/oas3-mdx",
"version": "0.3.5",
"description": "Convert OpenAPI spec to Markdown files.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand All @@ -9,7 +9,7 @@
"templates"
],
"bin": {
"openapi2md": "dist/cli.js"
"oas3-mdx": "dist/cli.js"
},
"scripts": {
"example": "tsc && node dist/cli.js --spec example/petstore.json --o build/",
Expand All @@ -28,19 +28,21 @@
},
"repository": {
"type": "git",
"url": "git+https://github.com/synx-ai/openapi2md"
"url": "git+https://github.com/synx-ai/oas3-mdx"
},
"bugs": {
"url": "https://github.com/synx-ai/openapi2md/issues"
"url": "https://github.com/synx-ai/oas3-mdx/issues"
},
"keywords": [
"oas3",
"openapi",
"openapi3",
"codegen",
"docgen",
"generator",
"documentation",
"markdown"
"markdown",
"mdx"
],
"author": {
"name": "Carlos Rivera",
Expand Down Expand Up @@ -70,6 +72,7 @@
"lodash": "^4.17.21",
"oas-validator": "^5.0.5",
"openapi-sampler": "^1.0.0-beta.18",
"openapi-snippet": "^0.9.2",
"prettier": "^2.2.1",
"xml-js": "^1.6.11",
"yargs": "^16.2.0",
Expand Down
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# OpenAPI3 to Markdown converter
[![Travis Build Status](https://img.shields.io/travis/synx-ai/openapi2md?logo=travis)](https://travis-ci.com/synx-ai/openapi2md) [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/synx-ai/openapi2md/Node.js%20Package?label=package&logo=github)](https://github.com/synx-ai/openapi2md/actions/workflows/package.yml) [![npm](https://img.shields.io/npm/v/@synx-ai/openapi2md?logo=npm)](https://www.npmjs.com/package/@synx-ai/openapi2md) [![npm](https://img.shields.io/npm/dw/@synx-ai/openapi2md?logo=npm)](https://www.npmjs.com/package/@synx-ai/openapi2md) [![Coveralls](https://img.shields.io/coveralls/github/synx-ai/openapi2md?logo=coveralls)](https://coveralls.io/github/synx-ai/openapi2md)
[![Travis Build Status](https://img.shields.io/travis/synx-ai/oas3-mdx?logo=travis)](https://travis-ci.com/synx-ai/oas3-mdx) [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/synx-ai/oas3-mdx/Node.js%20Package?label=package&logo=github)](https://github.com/synx-ai/oas3-mdx/actions/workflows/package.yml) [![npm](https://img.shields.io/npm/v/@synx-ai/oas3-mdx?logo=npm)](https://www.npmjs.com/package/@synx-ai/oas3-mdx) [![npm](https://img.shields.io/npm/dw/@synx-ai/oas3-mdx?logo=npm)](https://www.npmjs.com/package/@synx-ai/oas3-mdx) [![Coveralls](https://img.shields.io/coveralls/github/synx-ai/oas3-mdx?logo=coveralls)](https://coveralls.io/github/synx-ai/oas3-mdx)


Convert OpenAPI v3 spec into a directory of markdown files based on your spec paths. The purpose of this tool is to boost documentation generation and seamlessly integrate them into static site generators.
Expand Down
16 changes: 11 additions & 5 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,20 @@ const argv = yargs(hideBin(process.argv))
type: "string",
default: "../templates",
})
.option("snippets", {
alias: "c",
describe: "code snippet targets",
type: "string",
default: "shell",
})
.help().argv;

// call the convert function from ./index.js
convert(
path.resolve(process.cwd(), argv.spec),
path.resolve(process.cwd(), argv.target),
path.resolve(argv.templates)
)
convert(path.resolve(process.cwd(), argv.spec), {
outPath: path.resolve(process.cwd(), argv.target),
templatePath: path.resolve(argv.templates),
snippetTargets: argv.snippets.split(","),
})
.then(() => {
console.log(green("Done! ✨"));
})
Expand Down
54 changes: 53 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,24 @@ import * as Handlebars from "handlebars";
import * as _ from "lodash";
import * as xml from "xml-js";
import * as OpenAPISampler from "openapi-sampler";
import * as OpenAPISnippet from "openapi-snippet";

import * as prettier from "prettier";
import bundler from "./bundler";

/**
* Helper function to render a block of code
* @param {any} data the code as encoded string
* @param {any} lang code languaje
* @param {any} title snippet title
* @returns {string} a JSON serialized representation of the object
*/
const codeBlock = (data: string, lang: string = "", title: string = ""): string => {
const titleTag = title.length ? ` title="${title}"` : "";

return `\`\`\`${lang}${titleTag}\n${data}\n\`\`\``;
};

/**
* Helper function to serialize an object to JSON
* @param {any} data the object to serialize
Expand Down Expand Up @@ -45,15 +60,32 @@ const xmlCodeBlock = (elementName: string, data: any, title: string = ""): strin
return `\`\`\`${titleTag}xml\n${encoded}\n\`\`\``;
};

type Optional = {
/** @default "./build/" */
outPath?: string;

/** @default "../templates/" */
templatePath?: string;

/** @default ["curl"] */
snippetTargets?: string[];
};

/**
* Convert openapi spec to markdown
* @param {string} specFile specification file
* @param {string} outPath path to write documents
* @param {string} templatePath path to markdown templates
* @returns {Promise<void>}
*/
const convert = (specFile: string, outPath: string, templatePath: string = "../templates/"): Promise<void> => {
const convert = (specFile: string, options: Optional = {}): Promise<void> => {
return new Promise((resolve, reject) => {
const {
outPath = path.resolve(process.cwd(), "./build"),
templatePath = "../templates/",
snippetTargets = ["shell"],
} = options;

try {
// load the spec from a json into an object
bundler(specFile, "./")
Expand All @@ -62,6 +94,11 @@ const convert = (specFile: string, outPath: string, templatePath: string = "../t
// ToDo: delete existing path
}

Handlebars.registerHelper("codeSnippet", (content: string, lang: string, title: string) => {
// render code block
return codeBlock(content, lang, title);
});

Handlebars.registerHelper("schemaSample", (key: string, context: any) => {
const sampler = () => OpenAPISampler.sample(context, {}, spec);

Expand Down Expand Up @@ -91,6 +128,11 @@ const convert = (specFile: string, outPath: string, templatePath: string = "../t
return Object.keys(context)[0];
});

Handlebars.registerHelper("rawBlock", (context: any) => {
// returns firts key for an object, useful for default variables
return context.fn();
});

let pathTemplate;

if (fs.existsSync(path.resolve(process.cwd(), templatePath, "path.hdb"))) {
Expand All @@ -115,6 +157,15 @@ const convert = (specFile: string, outPath: string, templatePath: string = "../t
Object.keys(apiPath).forEach((methodKey: string) => {
const method = (apiPath as any)[methodKey];

// generate snippets for this endpoint
const generatedCode = OpenAPISnippet.getEndpointSnippets(spec, pathKey, methodKey, snippetTargets);

Object.values(generatedCode.snippets).forEach((snippet: { [k: string]: any }) => {
const { id } = snippet as any;

snippet.lang = id.split("_")[0].replace("node", "javascript");
});

// render the path using Handlebars and save it
fs.writeFileSync(
`${outPath}${pathKey}/${methodKey}.md`,
Expand All @@ -124,6 +175,7 @@ const convert = (specFile: string, outPath: string, templatePath: string = "../t
path: pathKey,
httpMethod: _.toUpper(methodKey),
method: method,
snippets: generatedCode.snippets,
}),
{
parser: "markdown",
Expand Down
6 changes: 6 additions & 0 deletions templates/path.hdb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ slug: {{slug}}
{{/with}} {{! requestBody }}
{{/if}} {{! requestBody }}

## Code Snippets

{{#each ../snippets}}
{{{codeSnippet content lang title}}}
{{/each}}

## Responses

{{#each responses}}
Expand Down
14 changes: 7 additions & 7 deletions tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,31 @@ const urlThatNotExists = "https://petstore3.synx.io/api/v3/openapi.json";
describe("convert()", () => {

it("should execute from file", () => {
return expect(convert(fileThatExists, "./build")).resolves.toBeUndefined();
return expect(convert(fileThatExists, { outPath: "./build" })).resolves.toBeUndefined();
});

it("should reject from wrong template dir", () => {
return expect(convert(fileThatExists, "./build", "./no-templates")).rejects.toBe("Can not find templates path");
return expect(convert(fileThatExists, { outPath: "./build", templatePath: "./no-templates" })).rejects.toBe("Can not find templates path");
});

it("should reject from file", () => {
return expect(convert(fileThatNotExists, "./build")).rejects.toBe("Can not load the content of the OpenAPI specification file");
return expect(convert(fileThatNotExists, { outPath: "./build" })).rejects.toBe("Can not load the content of the OpenAPI specification file");
});

it("should reject from wrong file", () => {
return expect(convert(fileThatExistsButIsWrong, "./build")).rejects.toMatch("Invalid OpenAPI file");
return expect(convert(fileThatExistsButIsWrong, { outPath: "./build" })).rejects.toMatch("Invalid OpenAPI file");
});

it("should reject from wrong file", () => {
return expect(convert(fileThatExistsInAnotherFormat, "./build")).rejects.toMatch("Can not parse the content");
return expect(convert(fileThatExistsInAnotherFormat, { outPath: "./build" })).rejects.toMatch("Can not parse the content");
});

it("should execute from url", () => {
return expect(convert(urlThatExists, "./build")).resolves.toBeUndefined();
return expect(convert(urlThatExists, { outPath: "./build" })).rejects.toBeDefined();
});

it("should reject from url", () => {
return expect(convert(urlThatNotExists, "./build")).rejects.toBe("Can not load the content of the OpenAPI specification file");
return expect(convert(urlThatNotExists, { outPath: "./build" })).rejects.toBe("Can not load the content of the OpenAPI specification file");
});

});
Loading

0 comments on commit 0044e6c

Please sign in to comment.