diff --git a/.gitignore b/.gitignore index 3ee92d22..c6559e9c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ temp.json .idea .DS_Store *.iml +/npm-debug.log diff --git a/lib/exporters/baseraml.js b/lib/exporters/baseraml.js index 5fef0b5e..08b168aa 100644 --- a/lib/exporters/baseraml.js +++ b/lib/exporters/baseraml.js @@ -116,7 +116,7 @@ RAML.prototype._mapSecurityScheme = function(slSecuritySchemes) { content.headers = {}; for (var i in slSecuritySchemes.apiKey.headers) { if (!slSecuritySchemes.apiKey.headers.hasOwnProperty(i)) continue; - + var q = slSecuritySchemes.apiKey.headers[i]; var keyName = q.name; content.headers[keyName] = { @@ -133,7 +133,7 @@ RAML.prototype._mapSecurityScheme = function(slSecuritySchemes) { content.queryParameters = {}; for (var i in slSecuritySchemes.apiKey.queryString) { if (!slSecuritySchemes.apiKey.queryString.hasOwnProperty(i)) continue; - + var q = slSecuritySchemes.apiKey.queryString[i]; var keyName = q.name; content.queryParameters[keyName] = { @@ -208,7 +208,7 @@ RAML.prototype._validateParam = function(params) { RAML.prototype._mapRequestBody = function(bodyData, mimeType){ var body = {}; if (!bodyData.body || mimeType === '') return body; - + switch(mimeType) { case 'application/json': body[mimeType] = this.mapBody(bodyData); @@ -226,13 +226,13 @@ RAML.prototype._mapRequestBody = function(bodyData, mimeType){ if (bodyData.description) { body[mimeType].description = bodyData.description; } - + return body; }; RAML.prototype._mapNamedParams = function(params){ if (!params || _.isEmpty(params.properties)) return; - + var newParams = {}; for (var key in params.properties) { if (!params.properties.hasOwnProperty(key)) continue; @@ -322,7 +322,7 @@ function mapProtocols(protocols) { RAML.prototype._mapTextSections = function(slTexts) { var results = []; if (!slTexts) return resilts; - + for (var i in slTexts) { if (!slTexts.hasOwnProperty(i)) continue; var text = slTexts[i]; @@ -397,6 +397,7 @@ RAML.prototype.convertRefFromModel = function(object) { RAML.prototype._mapTraits = function(slTraits, mimeType) { var traits = []; + var traitMap = {}; for (var i in slTraits) { if (!slTraits.hasOwnProperty(i)) continue; @@ -404,14 +405,14 @@ RAML.prototype._mapTraits = function(slTraits, mimeType) { trait = {}; try { - var queryString = JSON.parse(slTrait.request.queryString); + var queryString = jsonHelper.parse(slTrait.request.queryString); if (!jsonHelper.isEmptySchema(queryString)) { trait.queryParameters = this._mapNamedParams(queryString); } } catch(e) {} try { - var headers = JSON.parse(slTrait.request.headers); + var headers = jsonHelper.parse(slTrait.request.headers); if (!jsonHelper.isEmptySchema(headers)) { trait.headers = this._mapNamedParams(headers); } @@ -423,9 +424,15 @@ RAML.prototype._mapTraits = function(slTraits, mimeType) { } } catch(e) {} + var traitKey = _.camelCase(slTrait.name); var newTrait = {}; - newTrait[_.camelCase(slTrait.name)] = trait; + newTrait[traitKey] = trait; traits.push(newTrait); + traitMap[traitKey] = trait; + } + + if (this.version() === '1.0') { + return traitMap; } return traits; @@ -637,7 +644,7 @@ RAML.prototype._export = function () { } }; } - + if (this.hasInfo) { ramlDef.annotationTypes.info = { properties: { @@ -689,7 +696,7 @@ RAML.prototype._unescapeYamlIncludes = function(yaml) { RAML.prototype._getData = function(format) { switch (format) { case 'yaml': - var yaml = this._unescapeYamlIncludes(YAML.dump(JSON.parse(JSON.stringify(this.Data)), {lineWidth: -1})); + var yaml = this._unescapeYamlIncludes(YAML.dump(jsonHelper.parse(JSON.stringify(this.Data)), {lineWidth: -1})); return '#%RAML ' + this.version() + '\n'+yaml; default: throw Error('RAML doesn not support '+format+' format'); diff --git a/lib/exporters/raml10.js b/lib/exporters/raml10.js index a004b49c..f7bc92d0 100644 --- a/lib/exporters/raml10.js +++ b/lib/exporters/raml10.js @@ -48,9 +48,12 @@ RAML10.prototype.mapAuthorizationGrants = function(flow) { RAML10.prototype.mapBody = function(bodyData) { var body = jsonHelper.parse(bodyData.body); var result = this.convertAllOfToModel(this.convertRefFromModel(body)); - if (bodyData.example) { - result.example = jsonHelper.format(bodyData.example); - } + + var example = jsonHelper.format(result.example); + if (!_.isEmpty(example)) { + result.example = example; + } + return result; }; @@ -94,14 +97,14 @@ RAML10.prototype.convertAllOfToModel = function(object) { var val = object[id]; if (!val) continue; - + if (id == 'allOf') { object = this.convertAllOfAttribute(object); } else if (typeof val === 'object') { object[id] = this.convertAllOfToModel(val); } } - + return object; }; @@ -109,7 +112,7 @@ RAML10.prototype.convertAllOfToModel = function(object) { RAML10.prototype.convertAllOfAttribute = function(definition) { var allOfTypes = []; if (!definition.allOf) return definition; - + for (var j in definition.allOf){ if (!definition.allOf.hasOwnProperty(j)) continue; var allOf = definition.allOf[j]; @@ -122,7 +125,7 @@ RAML10.prototype.convertAllOfAttribute = function(definition) { } } definition.type = allOfTypes.length > 1 ? allOfTypes : allOfTypes[0]; - + delete definition.allOf; return definition; @@ -134,7 +137,7 @@ RAML10.prototype.mapSchema = function(slSchemas) { if (!slSchemas.hasOwnProperty(i)) continue; var schema = slSchemas[i]; var definition = this.convertRefFromModel(jsonHelper.parse(schema.Definition)); - + if (definition.allOf) { definition = this.convertAllOfToModel(definition); } else { @@ -142,11 +145,12 @@ RAML10.prototype.mapSchema = function(slSchemas) { definition = this.mapSchemaProperties(definition); } } - - if (schema.example) { - definition.example = jsonHelper.parse(schema.example); + + var example = jsonHelper.parse(schema.example); + if (!_.isEmpty(example)) { + definition.example = example; } - + results[schema.NameSpace] = definition; } return results; @@ -158,7 +162,7 @@ RAML10.prototype.mapSchemaProperties = function(definition) { var property = definition.properties[k]; property.required = false; } - + if (definition.required && definition.required.length > 0) { for(var j in definition.required) { if (!definition.required.hasOwnProperty(j)) continue; @@ -170,16 +174,16 @@ RAML10.prototype.mapSchemaProperties = function(definition) { } delete definition.required; } - + if (definition.additionalProperties) { definition.properties['//'] = definition.additionalProperties; delete definition.additionalProperties; } - + if (definition.properties && definition.type == 'object') { delete definition.type; } - + return definition; }; diff --git a/lib/importers/baseraml.js b/lib/importers/baseraml.js index 0b5ee630..d284e798 100644 --- a/lib/importers/baseraml.js +++ b/lib/importers/baseraml.js @@ -177,18 +177,26 @@ RAML.prototype.isValidRefValue = function (value) { return typeof value === 'string' && ramlHelper.getScalarTypes.indexOf(value) < 0 && value !== 'object'; }; -// from type=type1 to ref=type1 +// from type=type1 & schema=type1 to ref=type1 RAML.prototype.convertRefToModel = function(object) { + // if the object is a string, that means it's a direct ref/type + if (typeof object === 'string') { + return { + $ref: '#/definitions/' + object + }; + } + + for (var id in object) { + var isType = id == 'type'; - for (var id in object) { if (!object.hasOwnProperty(id)) continue; - if (id == 'type' && _.isArray(object[id]) && object[id].length == 1) { + if (isType && _.isArray(object[id]) && object[id].length == 1) { object[id] = object[id][0]; } var val = object[id]; if (!val) continue; - if (id == 'type' && this.isValidRefValues(val)) { + if (isType && this.isValidRefValues(val)) { object.ref = val; delete object[id]; } @@ -481,8 +489,10 @@ RAML.prototype._import = function() { this.project.Environment.SecuritySchemes = this._mapSecuritySchemes(this.data.securitySchemes); var resources = this.data.resources; - for (var i = 0; i < resources.length; i++) { - this._mapEndpoint(resources[i], '', {}); + if (!_.isEmpty(resources)) { + for (var i = 0; i < resources.length; i++) { + this._mapEndpoint(resources[i], '', {}); + } } var schemas = this._mapSchema(this.getSchema(this.data)); diff --git a/test/data/raml-import/raml/raml08-ref.yaml b/test/data/raml-import/raml/raml08-ref.yaml new file mode 100644 index 00000000..0b0c560b --- /dev/null +++ b/test/data/raml-import/raml/raml08-ref.yaml @@ -0,0 +1,22 @@ +#%RAML 0.8 +baseUri: https://api.example.com +title: Filesystem API +version: 0.1 +schemas: + - Admin User: | + { + "type": "object", + "properties": { + "input": { + "required": false, + "type": "string" + } + } + } +/files: + get: + responses: + 200: + body: + application/json: + schema: Admin User diff --git a/test/data/raml-import/swagger/raml08-ref.json b/test/data/raml-import/swagger/raml08-ref.json new file mode 100644 index 00000000..048115f4 --- /dev/null +++ b/test/data/raml-import/swagger/raml08-ref.json @@ -0,0 +1,41 @@ +{ + "swagger": "2.0", + "info": { + "title": "Filesystem API", + "version": "0.1", + "description": "" + }, + "host": "api.example.com", + "basePath": "/", + "schemes": [ + "https" + ], + "paths": { + "/files": { + "get": { + "operationId": "GET_files", + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/Admin User" + } + } + } + } + } + }, + "definitions": { + "Admin User": { + "type": "object", + "properties": { + "input": { + "type": "string" + } + } + } + } +} diff --git a/test/data/raml-import/swagger/raml10-include-fsresolver-type.json b/test/data/raml-import/swagger/raml10-include-fsresolver-type.json index 0f4efb17..ed5b6452 100644 --- a/test/data/raml-import/swagger/raml10-include-fsresolver-type.json +++ b/test/data/raml-import/swagger/raml10-include-fsresolver-type.json @@ -9,7 +9,9 @@ "description": "Error details", "type": "object" }, - "Foo": "can not resolve Person.xyz" + "Foo": { + "$ref": "#/definitions/can not resolve Person.xyz" + } }, "host": "rest-api.baeldung.com", "info": { @@ -208,4 +210,4 @@ } }, "swagger": "2.0" -} \ No newline at end of file +} diff --git a/test/data/raml-import/swagger/raml10-include-type.json b/test/data/raml-import/swagger/raml10-include-type.json index b11d4bcc..9ec90ff9 100644 --- a/test/data/raml-import/swagger/raml10-include-type.json +++ b/test/data/raml-import/swagger/raml10-include-type.json @@ -9,7 +9,9 @@ "description": "Error details", "type": "object" }, - "Foo": "can not resolve types/Foo.json" + "Foo": { + "$ref": "#/definitions/can not resolve types/Foo.json" + } }, "host": "rest-api.baeldung.com", "info": { @@ -208,4 +210,4 @@ } }, "swagger": "2.0" -} \ No newline at end of file +} diff --git a/test/data/swagger-import/raml/swagger-trait-to-raml08.yaml b/test/data/swagger-import/raml/swagger-trait-to-raml08.yaml new file mode 100644 index 00000000..5d5eb9bf --- /dev/null +++ b/test/data/swagger-import/raml/swagger-trait-to-raml08.yaml @@ -0,0 +1,16 @@ +#%RAML 0.8 +title: Test +documentation: + - + content: '' + title: 'Test' +traits: + - foo: + headers: + auth: + type: string + queryParameters: + limit: + type: string + responses: + '404': {} diff --git a/test/data/swagger-import/raml/swagger-trait-to-raml10.yaml b/test/data/swagger-import/raml/swagger-trait-to-raml10.yaml new file mode 100644 index 00000000..3feb0eb9 --- /dev/null +++ b/test/data/swagger-import/raml/swagger-trait-to-raml10.yaml @@ -0,0 +1,12 @@ +#%RAML 1.0 +title: Test +traits: + foo: + headers: + auth: + type: string + queryParameters: + limit: + type: string + responses: + '404': {} diff --git a/test/data/swagger-import/swagger/swagger-trait-to-raml08.json b/test/data/swagger-import/swagger/swagger-trait-to-raml08.json new file mode 100644 index 00000000..6d465983 --- /dev/null +++ b/test/data/swagger-import/swagger/swagger-trait-to-raml08.json @@ -0,0 +1,34 @@ +{ + "swagger": "2.0", + "info": { + "version": "", + "title": "Test", + "description": "" + }, + "paths": {}, + "parameters": { + "trait:foo:limit": { + "name": "limit", + "in": "query", + "type": "string" + }, + "trait:foo:auth": { + "name": "auth", + "in": "header", + "type": "string" + } + }, + "responses": { + "trait:foo:404": { + "description": "", + "schema": { + "type": "object", + "properties": { + "test": { + "type": "string" + } + } + } + } + } +} diff --git a/test/data/swagger-import/swagger/swagger-trait-to-raml10.json b/test/data/swagger-import/swagger/swagger-trait-to-raml10.json new file mode 100644 index 00000000..6d465983 --- /dev/null +++ b/test/data/swagger-import/swagger/swagger-trait-to-raml10.json @@ -0,0 +1,34 @@ +{ + "swagger": "2.0", + "info": { + "version": "", + "title": "Test", + "description": "" + }, + "paths": {}, + "parameters": { + "trait:foo:limit": { + "name": "limit", + "in": "query", + "type": "string" + }, + "trait:foo:auth": { + "name": "auth", + "in": "header", + "type": "string" + } + }, + "responses": { + "trait:foo:404": { + "description": "", + "schema": { + "type": "object", + "properties": { + "test": { + "type": "string" + } + } + } + } + } +} diff --git a/test/lib/converter.js b/test/lib/converter.js index 7165757b..53231f3d 100644 --- a/test/lib/converter.js +++ b/test/lib/converter.js @@ -171,15 +171,15 @@ describe('Converter', function() { describe('reversable - from swagger 2 raml 2 swagger', function () { var baseDir = __dirname + '/../data/reversable/swagger'; var testFiles = fs.readdirSync(baseDir); - + var testWithData = function (testFile) { - return function (done) { + return function (done) { var testFilePath = baseDir + '/' + testFile; - + var ramlVersion = _.startsWith(testFile, 'raml08') ? specConverter.Formats.RAML08 : specConverter.Formats.RAML10; var swaggerToRamlConverter = new specConverter.Converter(specConverter.Formats.SWAGGER, ramlVersion); var ramlToSwaggerConverter = new specConverter.Converter(ramlVersion, specConverter.Formats.SWAGGER); - + swaggerToRamlConverter.loadFile(testFilePath, function(){ try{ swaggerToRamlConverter.convert('yaml', function(err, covertedRAML){ @@ -204,9 +204,11 @@ describe('reversable - from swagger 2 raml 2 swagger', function () { }); }; }; - + testFiles.forEach(function (testFile) { - it('test: ' + testFile, testWithData(testFile)); + if (!_.startsWith(testFile, '.')) { + it('test: ' + testFile, testWithData(testFile)); + } }); }); @@ -214,15 +216,15 @@ describe('reversable - from swagger 2 raml 2 swagger', function () { describe('reversable - from raml 2 swagger 2 raml', function () { var baseDir = __dirname + '/../data/reversable/raml'; var testFiles = fs.readdirSync(baseDir); - + var testWithData = function (testFile) { return function (done) { var testFilePath = baseDir + '/' + testFile; - - var ramlVersion = _.startsWith(testFile, 'raml08') ? specConverter.Formats.RAML08 : specConverter.Formats.RAML10; + + var ramlVersion = _.includes(testFile, 'raml08') ? specConverter.Formats.RAML08 : specConverter.Formats.RAML10; var ramlToSwaggerConverter = new specConverter.Converter(ramlVersion, specConverter.Formats.SWAGGER); var swaggerToRamlConverter = new specConverter.Converter(specConverter.Formats.SWAGGER, ramlVersion); - + ramlToSwaggerConverter.loadFile(testFilePath, function(){ try{ ramlToSwaggerConverter.convert('json', function(err, resultSwagger){ @@ -247,41 +249,45 @@ describe('reversable - from raml 2 swagger 2 raml', function () { }); }; }; - + testFiles.forEach(function (testFile) { - it('test: ' + testFile, testWithData(testFile)); + if (!_.startsWith(testFile, '.')) { + it('test: ' + testFile, testWithData(testFile)); + } }); }); describe('from swagger to raml', function () { var baseDir = __dirname + '/../data/swagger-import/swagger'; var testFiles = fs.readdirSync(baseDir); - + var testWithData = function (sourceFile, targetFile, stringCompare) { return function (done) { - var converter = new specConverter.Converter(specConverter.Formats.SWAGGER, specConverter.Formats.RAML10); + var ramlVersion = _.includes(sourceFile, 'raml08') ? specConverter.Formats.RAML08 : specConverter.Formats.RAML10; + + var converter = new specConverter.Converter(specConverter.Formats.SWAGGER, ramlVersion); converter.loadFile(sourceFile, function(){ try{ converter.convert('yaml', function(err, covertedRAML){ if (err)return done(err); - + var existsTarget = fs.existsSync(targetFile); - + if (!existsTarget) { console.log('Content for non existing target file ' + targetFile + '\n.'); console.log('********** Begin file **********\n'); console.log(covertedRAML); console.log('********** Finish file **********\n'); - + done(err); } - + if (stringCompare == true) { expect(covertedRAML).to.deep.equal(fs.readFileSync(targetFile, 'utf8')); } else { expect(YAML.safeLoad(covertedRAML)).to.deep.equal(YAML.safeLoad(fs.readFileSync(targetFile, 'utf8'))); } - + done(); }); } catch(err) { @@ -290,14 +296,16 @@ describe('from swagger to raml', function () { }); }; }; - + testFiles.forEach(function (testFile) { - var sourceFile = baseDir + '/' + testFile; - var targetFile = baseDir + '/../raml/' + _.replace(testFile, 'json', 'yaml'); - - it('test: ' + testFile, testWithData(sourceFile, targetFile, false)); + if (!_.startsWith(testFile, '.')) { + var sourceFile = baseDir + '/' + testFile; + var targetFile = baseDir + '/../raml/' + _.replace(testFile, 'json', 'yaml'); + + it('test: ' + testFile, testWithData(sourceFile, targetFile, false)); + } }); - + it('should convert from swagger petstore with external refs to raml 1.0', testWithData(__dirname + '/../data/petstore-separate/spec/swagger.json', __dirname + '/../data/petstore-separate/raml10.yaml', true)); }); @@ -305,7 +313,7 @@ describe('from swagger to raml', function () { describe('from raml to swagger', function () { var baseDir = __dirname + '/../data/raml-import/raml'; var testFiles = fs.readdirSync(baseDir); - + var testWithData = function (testFile) { return function (done) { var testFilePath = baseDir + '/' + testFile; @@ -324,8 +332,10 @@ describe('from raml to swagger', function () { }); }; }; - + testFiles.forEach(function (testFile) { - it('test: ' + testFile, testWithData(testFile)); + if (!_.startsWith(testFile, '.')) { + it('test: ' + testFile, testWithData(testFile)); + } }); });