diff --git a/package.json b/package.json index 8fd7899..b447ee8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "apib2swagger", - "version": "1.3.0", + "version": "1.3.1", "description": "Convert API Blueprint to Swagger.", "bin": "./bin/apib2swagger.js", "scripts": { diff --git a/src/escape_json_pointer.js b/src/escape_json_pointer.js index a28c26b..0556e77 100644 --- a/src/escape_json_pointer.js +++ b/src/escape_json_pointer.js @@ -1,7 +1,7 @@ -// RFC 6901 -function escapeJSONPointer(input) { - s = input.replace(/~/g, '~0') - return s.replace(/\//g, '~1') -} - -module.exports = escapeJSONPointer; +// RFC 6901 +function escapeJSONPointer(input) { + s = input.replace(/~/g, '~0') + return s.replace(/\//g, '~1') +} + +module.exports = escapeJSONPointer; diff --git a/src/mson_to_json_schema.js b/src/mson_to_json_schema.js index f6788e8..6d7da19 100644 --- a/src/mson_to_json_schema.js +++ b/src/mson_to_json_schema.js @@ -1,93 +1,93 @@ -var escapeJSONPointer = require('./escape_json_pointer'); - -function convertMsonToJsonSchema(content) { - // for apib._version = "4.0" - var mson = content.content[0]; - if (mson.element === 'array') { - if (!mson.content || mson.content.length === 0) { - return {type: 'array', items: {}}; - } else if (mson.content.length === 1) { - return {type: 'array', items: {'$ref': '#/definitions/' + escapeJSONPointer(mson.content[0].element)}}; - } else if (mson.content.length > 1) { - var items = []; - for (var i = 0; i < mson.content.length; i++) { - items.push({'$ref': '#/definitions/' + escapeJSONPointer(mson.content[i].element)}); - } - return {type: 'array', items: {'anyOf': items}}; - } - } - if (mson.element === 'enum') { - return convertEnum(mson.content); - } - if (mson.element !== 'object' && !mson.content) { - return {'$ref': '#/definitions/' + escapeJSONPointer(mson.element)}; - } - // object - var schema = {}; - schema.type = 'object'; - schema.required = []; - schema.properties = {}; - for (var j = 0; j < mson.content.length; j++) { - var member = mson.content[j]; - if (member.element !== "member") continue; - // MEMO: member.meta.description - if (member.content.value.element === 'array') { - // TODO: use member.content.value.content (schema for items) - schema.properties[member.content.key.content] = {type: 'array', items: {}}; - } else if (member.content.value.element === 'enum') { - var body = {type: member.content.key.element}; - body.enum = member.content.value.content.map(function(a) { - return a.content; - }); - schema.properties[member.content.key.content] = body; - } else { - schema.properties[member.content.key.content] = {type: member.content.value.element}; - } - if (!member.attributes || !member.attributes.typeAttributes) continue; - for (var k = 0; k < member.attributes.typeAttributes.length; k++) { - if (member.attributes.typeAttributes[k] === "fixedType") { - // handle when we have attributes containing objects - if (member.content.value.element === 'array'){ - schema.properties[member.content.key.content] = { - 'type': "array", - 'items': { - '$ref': '#/definitions/' + escapeJSONPointer(member.content.value.content[0].element) - } - }; - } else { - schema.properties[member.content.key.content] = {'$ref': '#/definitions/' + escapeJSONPointer(member.content.value.element)}; - } - } - if (member.attributes.typeAttributes[k] === "required") { - schema.required.push(member.content.key.content); - } - } - } - - // According to schema definition, required is a stringArray, which must be non-empty - if (schema.required.length === 0) { - delete schema.required - } - - if (mson.element !== 'object') { - return {'allOf': [{'$ref':'#/definitions/' + escapeJSONPointer(mson.element)}, schema]}; - } - - return schema; -} - -function convertEnum(contents) { - var schema = {type: '', enum: []}; - for (var i = 0; i < contents.length; i++) { - var content = contents[i]; - if (!schema.type) { - schema.type = content.element; - } else if (schema.type != content.element) { - // WARN!! mixed type enum - } - schema.enum.push(content.content); - } - return schema; -} - +var escapeJSONPointer = require('./escape_json_pointer'); + +function convertMsonToJsonSchema(content) { + // for apib._version = "4.0" + var mson = content.content[0]; + if (mson.element === 'array') { + if (!mson.content || mson.content.length === 0) { + return {type: 'array', items: {}}; + } else if (mson.content.length === 1) { + return {type: 'array', items: {'$ref': '#/definitions/' + escapeJSONPointer(mson.content[0].element)}}; + } else if (mson.content.length > 1) { + var items = []; + for (var i = 0; i < mson.content.length; i++) { + items.push({'$ref': '#/definitions/' + escapeJSONPointer(mson.content[i].element)}); + } + return {type: 'array', items: {'anyOf': items}}; + } + } + if (mson.element === 'enum') { + return convertEnum(mson.content); + } + if (mson.element !== 'object' && !mson.content) { + return {'$ref': '#/definitions/' + escapeJSONPointer(mson.element)}; + } + // object + var schema = {}; + schema.type = 'object'; + schema.required = []; + schema.properties = {}; + for (var j = 0; mson.content && j < mson.content.length; j++) { + var member = mson.content[j]; + if (member.element !== "member") continue; + // MEMO: member.meta.description + if (member.content.value.element === 'array') { + // TODO: use member.content.value.content (schema for items) + schema.properties[member.content.key.content] = {type: 'array', items: {}}; + } else if (member.content.value.element === 'enum') { + var body = {type: member.content.key.element}; + body.enum = member.content.value.content.map(function(a) { + return a.content; + }); + schema.properties[member.content.key.content] = body; + } else { + schema.properties[member.content.key.content] = {type: member.content.value.element}; + } + if (!member.attributes || !member.attributes.typeAttributes) continue; + for (var k = 0; k < member.attributes.typeAttributes.length; k++) { + if (member.attributes.typeAttributes[k] === "fixedType") { + // handle when we have attributes containing objects + if (member.content.value.element === 'array'){ + schema.properties[member.content.key.content] = { + 'type': "array", + 'items': { + '$ref': '#/definitions/' + escapeJSONPointer(member.content.value.content[0].element) + } + }; + } else { + schema.properties[member.content.key.content] = {'$ref': '#/definitions/' + escapeJSONPointer(member.content.value.element)}; + } + } + if (member.attributes.typeAttributes[k] === "required") { + schema.required.push(member.content.key.content); + } + } + } + + // According to schema definition, required is a stringArray, which must be non-empty + if (schema.required.length === 0) { + delete schema.required + } + + if (mson.element !== 'object') { + return {'allOf': [{'$ref':'#/definitions/' + escapeJSONPointer(mson.element)}, schema]}; + } + + return schema; +} + +function convertEnum(contents) { + var schema = {type: '', enum: []}; + for (var i = 0; i < contents.length; i++) { + var content = contents[i]; + if (!schema.type) { + schema.type = content.element; + } else if (schema.type != content.element) { + // WARN!! mixed type enum + } + schema.enum.push(content.content); + } + return schema; +} + module.exports = convertMsonToJsonSchema; \ No newline at end of file diff --git a/test/input/Issue-#35.md b/test/input/Issue-#35.md new file mode 100644 index 0000000..ec749af --- /dev/null +++ b/test/input/Issue-#35.md @@ -0,0 +1,8 @@ +FORMAT: 1A + +# Data Structures + +# some category of data structures +## Config ++ alice (string, required) - information about alice ++ bob (string, required) - information about bob diff --git a/test/output/Issue-#35.json b/test/output/Issue-#35.json new file mode 100644 index 0000000..d1071e6 --- /dev/null +++ b/test/output/Issue-#35.json @@ -0,0 +1,31 @@ +{ + "swagger": "2.0", + "info": { + "title": "", + "version": "", + "description": "" + }, + "paths": {}, + "definitions": { + "some category of data structures": { + "type": "object", + "properties": {} + }, + "Config": { + "type": "object", + "required": [ + "alice", + "bob" + ], + "properties": { + "alice": { + "type": "string" + }, + "bob": { + "type": "string" + } + } + } + }, + "tags": [] +} \ No newline at end of file diff --git a/test/test.js b/test/test.js index bc6bb7f..c030cb0 100644 --- a/test/test.js +++ b/test/test.js @@ -32,6 +32,7 @@ var remote = 'https://raw.githubusercontent.com/apiaryio/api-blueprint/format-1A 'Issue-#26.md', 'Issue-#29.md', 'Issue-#33.md', + 'Issue-#35.md', 'apiblueprint_uber.md', 'apiblueprint_valid_simple.md' ];