Skip to content

Commit

Permalink
Feature/yaml input definition (#105)
Browse files Browse the repository at this point in the history
* Allow YAML specification files as input

* Update README.md to specify YAML can be input

* Unit tests CLI specification input files
  • Loading branch information
ehmicky authored and kalinchernev committed Sep 16, 2018
1 parent 4627728 commit 06faa89
Show file tree
Hide file tree
Showing 12 changed files with 208 additions and 83 deletions.
57 changes: 46 additions & 11 deletions bin/swagger-jsdoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,43 @@ function createSpecification(swaggerDefinition, apis, fileName) {
});
}

function loadJsSpecification(data, resolvedPath) {
// eslint-disable-next-line
return require(resolvedPath);
}

const YAML_OPTS = {
// OpenAPI spec mandates JSON-compatible YAML
schema: jsYaml.JSON_SCHEMA,
};

function loadYamlSpecification(data) {
return jsYaml.load(data, YAML_OPTS);
}

const LOADERS = {
'.js': loadJsSpecification,
'.json': JSON.parse,
'.yml': loadYamlSpecification,
'.yaml': loadYamlSpecification,
};

// Get an object of the definition file configuration.
function loadSpecification(defPath, data) {
const resolvedPath = path.resolve(defPath);

const extName = path.extname(resolvedPath);
const loader = LOADERS[extName];

// Check whether the definition file is actually a usable file
if (loader === undefined) {
throw new Error('Definition file should be .js, .json, .yml or .yaml');
}

const swaggerDefinition = loader(data, resolvedPath);
return swaggerDefinition;
}

program
.version(pkg.version)
.usage('[options] <path ...>')
Expand Down Expand Up @@ -85,18 +122,16 @@ fs.readFile(program.definition, 'utf-8', (err, data) => {
return console.log('Definition file provided is not good.');
}

// Check whether the definition file is actually a usable .js file
if (
path.extname(program.definition) !== '.js' &&
path.extname(program.definition) !== '.json'
) {
console.log('Format as a module, it will be imported with require().');
return console.log('Definition file should be .js or .json');
}
let swaggerDefinition;

// Get an object of the definition file configuration.
// eslint-disable-next-line
const swaggerDefinition = require(path.resolve(program.definition));
try {
swaggerDefinition = loadSpecification(program.definition, data);
} catch (error) {
const message = `Error while loading definition file '${
program.definition
}':\n${error.message}`;
return console.log(message);
}

// Check for info object in the definition.
if (!('info' in swaggerDefinition)) {
Expand Down
2 changes: 1 addition & 1 deletion docs/CLI.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Swagger-jsdoc will read the `apis` array in your definition file by default for
$ swagger-jsdoc -d swaggerDef.js -o doc.json
```

This could be any .js or .json file which will be `require()`-ed and parsed/validated as JSON.
This could be any .js, .json, .yml or .yaml file.

#### Specify input files (optional)

Expand Down
71 changes: 71 additions & 0 deletions test/cli/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,77 @@ describe('command line interface', () => {
});
});

it('should allow a JavaScript definition file', done => {
const goodInput = `${
process.env.PWD
}/bin/swagger-jsdoc.js -d test/fixtures/v2/api_definition.js`;
exec(goodInput, (error, stdout, stderr) => {
if (error) {
throw new Error(error, stderr);
}
expect(stdout).to.contain('Swagger specification is ready.');
done();
});
});

it('should allow a JSON definition file', done => {
const goodInput = `${
process.env.PWD
}/bin/swagger-jsdoc.js -d test/fixtures/api_definition.json`;
exec(goodInput, (error, stdout, stderr) => {
if (error) {
throw new Error(error, stderr);
}
expect(stdout).to.contain('Swagger specification is ready.');
done();
});
});

it('should reject definition file with invalid JSON syntax', done => {
const goodInput = `${
process.env.PWD
}/bin/swagger-jsdoc.js -d test/fixtures/wrong_syntax.json`;
exec(goodInput, (error, stdout) => {
expect(stdout).to.contain('Unexpected token t in JSON');
done();
});
});

it('should allow a YAML definition file', done => {
const goodInput = `${
process.env.PWD
}/bin/swagger-jsdoc.js -d test/fixtures/api_definition.yaml`;
exec(goodInput, (error, stdout, stderr) => {
if (error) {
throw new Error(error, stderr);
}
expect(stdout).to.contain('Swagger specification is ready.');
done();
});
});

it('should reject definition file with invalid YAML syntax', done => {
const goodInput = `${
process.env.PWD
}/bin/swagger-jsdoc.js -d test/fixtures/wrong_syntax.yaml`;
exec(goodInput, (error, stdout) => {
expect(stdout).to.contain('tag suffix cannot contain exclamation marks');
done();
});
});

it('should reject definition file with non-JSON compatible YAML syntax', done => {
const goodInput = `${
process.env.PWD
}/bin/swagger-jsdoc.js -d test/fixtures/non_json_compatible.yaml`;
exec(goodInput, (error, stdout) => {
expect(stdout).to.contain(
'unknown tag !<tag:yaml.org,2002:js/undefined>'
);
done();
});
});

// Cleanup test files if any.
after(() => {
const defaultSpecification = `${process.env.PWD}/swagger.json`;
Expand Down
81 changes: 37 additions & 44 deletions test/example/v2/swagger-spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,20 @@
"/login": {
"post": {
"description": "Login to the application",
"tags": [
"Users",
"Login"
],
"produces": [
"application/json"
"tags": ["Users", "Login"],
"produces": ["application/json"],
"parameters": [
{
"$ref": "#/parameters/username"
},
{
"name": "password",
"description": "User's password.",
"in": "formData",
"required": true,
"type": "string"
}
],
"parameters": [{
"$ref": "#/parameters/username"
}, {
"name": "password",
"description": "User's password.",
"in": "formData",
"required": true,
"type": "string"
}],
"responses": {
"200": {
"description": "login",
Expand All @@ -51,12 +49,8 @@
"/users": {
"get": {
"description": "Returns users",
"tags": [
"Users"
],
"produces": [
"application/json"
],
"tags": ["Users"],
"produces": ["application/json"],
"responses": {
"200": {
"description": "users"
Expand All @@ -65,15 +59,13 @@
},
"post": {
"description": "Returns users",
"tags": [
"Users"
],
"produces": [
"application/json"
"tags": ["Users"],
"produces": ["application/json"],
"parameters": [
{
"$ref": "#/parameters/username"
}
],
"parameters": [{
"$ref": "#/parameters/username"
}],
"responses": {
"200": {
"description": "users"
Expand All @@ -94,10 +86,7 @@
},
"definitions": {
"Login": {
"required": [
"username",
"password"
],
"required": ["username", "password"],
"properties": {
"username": {
"type": "string"
Expand All @@ -122,14 +111,18 @@
}
},
"securityDefinitions": {},
"tags": [{
"name": "Users",
"description": "User management and login"
}, {
"name": "Login",
"description": "Login"
}, {
"name": "Accounts",
"description": "Accounts"
}]
}
"tags": [
{
"name": "Users",
"description": "User management and login"
},
{
"name": "Login",
"description": "Login"
},
{
"name": "Accounts",
"description": "Accounts"
}
]
}
3 changes: 1 addition & 2 deletions test/example/v3/api-with-examples/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@
"application/json": {
"examples": {
"foo": {
"value":
"{\n \"versions\": [\n {\n \"status\": \"CURRENT\",\n \"updated\": \"2011-01-21T11:33:21Z\",\n \"id\": \"v2.0\",\n \"links\": [\n {\n \"href\": \"http://127.0.0.1:8774/v2/\",\n \"rel\": \"self\"\n }\n ]\n },\n {\n \"status\": \"EXPERIMENTAL\",\n \"updated\": \"2013-07-23T11:33:21Z\",\n \"id\": \"v3.0\",\n \"links\": [\n {\n \"href\": \"http://127.0.0.1:8774/v3/\",\n \"rel\": \"self\"\n }\n ]\n }\n ]\n}\n"
"value": "{\n \"versions\": [\n {\n \"status\": \"CURRENT\",\n \"updated\": \"2011-01-21T11:33:21Z\",\n \"id\": \"v2.0\",\n \"links\": [\n {\n \"href\": \"http://127.0.0.1:8774/v2/\",\n \"rel\": \"self\"\n }\n ]\n },\n {\n \"status\": \"EXPERIMENTAL\",\n \"updated\": \"2013-07-23T11:33:21Z\",\n \"id\": \"v3.0\",\n \"links\": [\n {\n \"href\": \"http://127.0.0.1:8774/v3/\",\n \"rel\": \"self\"\n }\n ]\n }\n ]\n}\n"
}
}
}
Expand Down
12 changes: 4 additions & 8 deletions test/example/v3/callback/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@
"name": "callbackUrl",
"in": "query",
"required": true,
"description":
"the location where data will be sent. Must be network accessible\nby the source server\n",
"description": "the location where data will be sent. Must be network accessible\nby the source server\n",
"schema": {
"type": "string",
"format": "uri",
Expand All @@ -32,8 +31,7 @@
"required": ["subscriptionId"],
"properties": {
"subscriptionId": {
"description":
"this unique identifier allows management of the subscription",
"description": "this unique identifier allows management of the subscription",
"type": "string",
"example": "2531329f-fb09-4ef7-887e-84e648214436"
}
Expand Down Expand Up @@ -67,12 +65,10 @@
},
"responses": {
"202": {
"description":
"Your server implementation should return this HTTP status code\nif the data was received successfully\n"
"description": "Your server implementation should return this HTTP status code\nif the data was received successfully\n"
},
"204": {
"description":
"Your server should return this HTTP status code if no longer interested\nin further updates\n"
"description": "Your server should return this HTTP status code if no longer interested\nin further updates\n"
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions test/fixtures/api_definition.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"info": {
"title": "Hello World",
"version": "1.0.0",
"description": "A sample API"
},
"apis": ["./**/*/routes.js"]
}
5 changes: 5 additions & 0 deletions test/fixtures/api_definition.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
info:
title: Hello World
version: 1.0.0
description: A sample API
apis: [./**/*/routes.js]
5 changes: 5 additions & 0 deletions test/fixtures/non_json_compatible.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
info:
title: !!js/undefined
version: 1.0.0
description: A sample API
apis: [./**/*/routes.js]
34 changes: 17 additions & 17 deletions test/fixtures/v2/swaggerObject.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
{
"info":{
"title":"Hello World",
"version":"1.0.0",
"description":"A sample API"
"info": {
"title": "Hello World",
"version": "1.0.0",
"description": "A sample API"
},
"host":"localhost:3000",
"basePath":"/",
"swagger":"2.0",
"schemes":[],
"consumes":[],
"produces":[],
"paths":{},
"definitions":{},
"responses":{},
"parameters":{},
"securityDefinitions":{},
"security":{},
"tags":[],
"host": "localhost:3000",
"basePath": "/",
"swagger": "2.0",
"schemes": [],
"consumes": [],
"produces": [],
"paths": {},
"definitions": {},
"responses": {},
"parameters": {},
"securityDefinitions": {},
"security": {},
"tags": [],
"externalDocs": {}
}
8 changes: 8 additions & 0 deletions test/fixtures/wrong_syntax.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"info": {
title: "Hello World",
"version": "1.0.0",
"description": "A sample API"
},
"apis": ["./**/*/routes.js"]
}
5 changes: 5 additions & 0 deletions test/fixtures/wrong_syntax.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
info:
!!!title: Hello World
version: 1.0.0
description: A sample API
apis: [./**/*/routes.js]

0 comments on commit 06faa89

Please sign in to comment.