diff --git a/packages/fury-adapter-oas3-parser/CHANGELOG.md b/packages/fury-adapter-oas3-parser/CHANGELOG.md index b039ab2a7..0db37c430 100644 --- a/packages/fury-adapter-oas3-parser/CHANGELOG.md +++ b/packages/fury-adapter-oas3-parser/CHANGELOG.md @@ -1,5 +1,11 @@ # Fury OAS3 Parser Changelog +## Master + +### Enhancements + +- Added support for `info.license` (License Object). + ## 0.9.1 (2019-08-08) ### Enhancements diff --git a/packages/fury-adapter-oas3-parser/STATUS.md b/packages/fury-adapter-oas3-parser/STATUS.md index 5ac8cc3e2..f0f5dde82 100644 --- a/packages/fury-adapter-oas3-parser/STATUS.md +++ b/packages/fury-adapter-oas3-parser/STATUS.md @@ -32,7 +32,7 @@ Key: | description | ✓ | | termsOfService | [✕](https://github.com/apiaryio/api-elements.js/issues/78) | | contact | [✕](https://github.com/apiaryio/api-elements.js/issues/79) | -| license | [✕](https://github.com/apiaryio/api-elements.js/issues/80) | +| license | ✓ | | version | ✓ | ## Paths Object diff --git a/packages/fury-adapter-oas3-parser/lib/parser/oas/parseInfoObject.js b/packages/fury-adapter-oas3-parser/lib/parser/oas/parseInfoObject.js index 49c6506ae..56029c931 100644 --- a/packages/fury-adapter-oas3-parser/lib/parser/oas/parseInfoObject.js +++ b/packages/fury-adapter-oas3-parser/lib/parser/oas/parseInfoObject.js @@ -5,16 +5,17 @@ const { createInvalidMemberWarning, } = require('../annotations'); const { - isObject, hasKey, isExtension, + isObject, hasKey, getValue, isExtension, } = require('../../predicates'); const parseObject = require('../parseObject'); const parseString = require('../parseString'); const parseCopy = require('../parseCopy'); const pipeParseResult = require('../../pipeParseResult'); +const parseLicenseObject = require('./parseLicenseObject'); const name = 'Info Object'; const requiredKeys = ['title', 'version']; -const unsupportedKeys = ['termsOfService', 'contact', 'license']; +const unsupportedKeys = ['termsOfService', 'contact']; /** * Returns whether the given member element is unsupported @@ -38,6 +39,7 @@ function parseInfo(context, info) { [hasKey('title'), parseString(context, name, true)], [hasKey('version'), parseString(context, name, true)], [hasKey('description'), parseCopy(context, name, false)], + [hasKey('license'), R.compose(parseLicenseObject(context), getValue)], [isUnsupportedKey, createUnsupportedMemberWarning(namespace, name)], // FIXME Support exposing extensions into parse result @@ -60,6 +62,10 @@ function parseInfo(context, info) { api.push(info.get('description')); } + if (info.get('license')) { + api.links.push(info.get('license')); + } + return api; }); diff --git a/packages/fury-adapter-oas3-parser/lib/parser/oas/parseLicenseObject.js b/packages/fury-adapter-oas3-parser/lib/parser/oas/parseLicenseObject.js new file mode 100644 index 000000000..128322060 --- /dev/null +++ b/packages/fury-adapter-oas3-parser/lib/parser/oas/parseLicenseObject.js @@ -0,0 +1,41 @@ + +const R = require('ramda'); +const { createWarning } = require('../../elements'); +const { + createInvalidMemberWarning, +} = require('../annotations'); +const { + isObject, hasKey, isExtension, +} = require('../../predicates'); +const parseObject = require('../parseObject'); +const parseString = require('../parseString'); +const pipeParseResult = require('../../pipeParseResult'); + +const name = 'License Object'; +const requiredKeys = ['name']; + +const parseMember = context => R.cond([ + [hasKey('name'), parseString(context, name, false)], + [hasKey('url'), parseString(context, name, false)], + [isExtension, () => new context.namespace.elements.ParseResult()], + [R.T, createInvalidMemberWarning(context.namespace, name)], +]); + +/** + * Parse the OpenAPI 'License Object' (`#/info/license`) + * @see http://spec.openapis.org/oas/v3.0.2#license-object + * @returns ParseResult + * @private + */ +const parseLicenseObject = context => pipeParseResult(context.namespace, + R.unless(isObject, createWarning(context.namespace, `'${name}' is not an object`)), + parseObject(context, name, parseMember(context), requiredKeys, [], true), + (object) => { + const link = new context.namespace.elements.Link(); + link.relation = 'license'; + link.title = object.get('name'); + link.href = object.getValue('url') || 'http://purl.org/atompub/license#unspecified'; + return link; + }); + +module.exports = parseLicenseObject; diff --git a/packages/fury-adapter-oas3-parser/test/integration/fixtures/petstore.json b/packages/fury-adapter-oas3-parser/test/integration/fixtures/petstore.json index fceca3c31..663e3abed 100644 --- a/packages/fury-adapter-oas3-parser/test/integration/fixtures/petstore.json +++ b/packages/fury-adapter-oas3-parser/test/integration/fixtures/petstore.json @@ -16,6 +16,30 @@ "title": { "element": "string", "content": "Swagger Petstore" + }, + "links": { + "element": "array", + "content": [ + { + "element": "link", + "meta": { + "title": { + "element": "string", + "content": "MIT" + } + }, + "attributes": { + "relation": { + "element": "string", + "content": "license" + }, + "href": { + "element": "string", + "content": "http://purl.org/atompub/license#unspecified" + } + } + } + ] } }, "attributes": { @@ -527,66 +551,6 @@ } ] }, - { - "element": "annotation", - "meta": { - "classes": { - "element": "array", - "content": [ - { - "element": "string", - "content": "warning" - } - ] - } - }, - "attributes": { - "sourceMap": { - "element": "array", - "content": [ - { - "element": "sourceMap", - "content": [ - { - "element": "array", - "content": [ - { - "element": "number", - "attributes": { - "line": { - "element": "number", - "content": 5 - }, - "column": { - "element": "number", - "content": 3 - } - }, - "content": 68 - }, - { - "element": "number", - "attributes": { - "line": { - "element": "number", - "content": 5 - }, - "column": { - "element": "number", - "content": 10 - } - }, - "content": 7 - } - ] - } - ] - } - ] - } - }, - "content": "'Info Object' contains unsupported key 'license'" - }, { "element": "annotation", "meta": { diff --git a/packages/fury-adapter-oas3-parser/test/integration/fixtures/petstore.sourcemap.json b/packages/fury-adapter-oas3-parser/test/integration/fixtures/petstore.sourcemap.json index a57c44ff2..937f633b5 100644 --- a/packages/fury-adapter-oas3-parser/test/integration/fixtures/petstore.sourcemap.json +++ b/packages/fury-adapter-oas3-parser/test/integration/fixtures/petstore.sourcemap.json @@ -41,6 +41,55 @@ } }, "content": "Swagger Petstore" + }, + "links": { + "element": "array", + "content": [ + { + "element": "link", + "meta": { + "title": { + "element": "string", + "attributes": { + "sourceMap": { + "element": "array", + "content": [ + { + "element": "sourceMap", + "content": [ + { + "element": "array", + "content": [ + { + "element": "number", + "content": 87 + }, + { + "element": "number", + "content": 3 + } + ] + } + ] + } + ] + } + }, + "content": "MIT" + } + }, + "attributes": { + "relation": { + "element": "string", + "content": "license" + }, + "href": { + "element": "string", + "content": "http://purl.org/atompub/license#unspecified" + } + } + } + ] } }, "attributes": { @@ -1277,66 +1326,6 @@ } ] }, - { - "element": "annotation", - "meta": { - "classes": { - "element": "array", - "content": [ - { - "element": "string", - "content": "warning" - } - ] - } - }, - "attributes": { - "sourceMap": { - "element": "array", - "content": [ - { - "element": "sourceMap", - "content": [ - { - "element": "array", - "content": [ - { - "element": "number", - "attributes": { - "line": { - "element": "number", - "content": 5 - }, - "column": { - "element": "number", - "content": 3 - } - }, - "content": 68 - }, - { - "element": "number", - "attributes": { - "line": { - "element": "number", - "content": 5 - }, - "column": { - "element": "number", - "content": 10 - } - }, - "content": 7 - } - ] - } - ] - } - ] - } - }, - "content": "'Info Object' contains unsupported key 'license'" - }, { "element": "annotation", "meta": { diff --git a/packages/fury-adapter-oas3-parser/test/unit/parser/oas/parseInfoObject-test.js b/packages/fury-adapter-oas3-parser/test/unit/parser/oas/parseInfoObject-test.js index 2c5387edf..467f92a19 100644 --- a/packages/fury-adapter-oas3-parser/test/unit/parser/oas/parseInfoObject-test.js +++ b/packages/fury-adapter-oas3-parser/test/unit/parser/oas/parseInfoObject-test.js @@ -111,18 +111,6 @@ describe('#parseInfoObject', () => { expect(parseResult).to.contain.warning("'Info Object' contains unsupported key 'contact'"); }); - it('provides warning for unsupported license key', () => { - const object = new namespace.elements.Object({ - title: 'My API', - version: '1.0.0', - license: {}, - }); - - const parseResult = parse(context, object); - - expect(parseResult).to.contain.warning("'Info Object' contains unsupported key 'license'"); - }); - it('does not provide warning for Info Object extensions', () => { const object = new namespace.elements.Object({ title: 'My API', @@ -172,4 +160,22 @@ describe('#parseInfoObject', () => { expect(parseResult.length).to.equal(1); expect(parseResult.api.copy.toValue()).to.deep.equal(['My API Description']); }); + + it('provides api category with license', () => { + const info = new namespace.elements.Object({ + title: 'My API', + version: '1.0.0', + license: { + name: 'Apache 2.0', + url: 'https://www.apache.org/licenses/LICENSE-2.0.html', + }, + }); + + const parseResult = parse(context, info); + expect(parseResult.length).to.equal(1); + + const license = parseResult.api.links.get(0); + expect(license.relation.toValue()).to.equal('license'); + expect(license.href.toValue()).to.equal('https://www.apache.org/licenses/LICENSE-2.0.html'); + }); }); diff --git a/packages/fury-adapter-oas3-parser/test/unit/parser/oas/parseLicenseObject-test.js b/packages/fury-adapter-oas3-parser/test/unit/parser/oas/parseLicenseObject-test.js new file mode 100644 index 000000000..9fa595e16 --- /dev/null +++ b/packages/fury-adapter-oas3-parser/test/unit/parser/oas/parseLicenseObject-test.js @@ -0,0 +1,114 @@ +const { Fury } = require('fury'); +const { expect } = require('../../chai'); + +const parse = require('../../../../lib/parser/oas/parseLicenseObject'); +const Context = require('../../../../lib/context'); + +const { minim: namespace } = new Fury(); +const { Link } = namespace.elements; + +describe('#parseLicenseObject', () => { + let context; + + beforeEach(() => { + context = new Context(namespace); + }); + + it('provides warning when license is non-object', () => { + const license = new namespace.elements.String(); + + const parseResult = parse(context)(license); + + expect(parseResult.length).to.equal(1); + expect(parseResult).to.contain.warning("'License Object' is not an object"); + }); + + describe('#name', () => { + it('provides warning for missing required name', () => { + const license = new namespace.elements.Object({}); + + const parseResult = parse(context)(license); + + expect(parseResult.length).to.equal(1); + expect(parseResult).to.contain.warning("'License Object' is missing required property 'name'"); + }); + + it('provides warning when name is non-string', () => { + const license = new namespace.elements.Object({ + name: 1, + }); + + const parseResult = parse(context)(license); + + expect(parseResult.length).to.equal(1); + expect(parseResult).to.contain.warning("'License Object' 'name' is not a string"); + }); + }); + + describe('#url', () => { + it('provides warning when description is non-string', () => { + const license = new namespace.elements.Object({ + name: 'Apache 2.0', + url: 1, + }); + + const parseResult = parse(context)(license); + expect(parseResult).to.contain.warning("'License Object' 'url' is not a string"); + }); + }); + + describe('warnings for unsupported properties', () => { + it('does not provide warning for license Object extensions', () => { + const object = new namespace.elements.Object({ + name: 'Apache 2.0', + 'x-extension': {}, + }); + + const parseResult = parse(context)(object); + + expect(parseResult).to.not.contain.annotations; + }); + + it('provides warning for invalid keys', () => { + const object = new namespace.elements.Object({ + name: 'Apache 2.0', + invalid: {}, + }); + + const parseResult = parse(context)(object); + + expect(parseResult).to.contain.warning("'License Object' contains invalid key 'invalid'"); + }); + }); + + it('provides license link for license with name', () => { + const license = new namespace.elements.Object({ + name: 'Apache 2.0', + }); + + const parseResult = parse(context)(license); + expect(parseResult.length).to.equal(1); + const link = parseResult.get(0); + + expect(link).to.be.instanceof(Link); + expect(link.relation.toValue()).to.equal('license'); + expect(link.title.toValue()).to.equal('Apache 2.0'); + expect(link.href.toValue()).to.equal('http://purl.org/atompub/license#unspecified'); + }); + + it('provides license link for license with name and url', () => { + const license = new namespace.elements.Object({ + name: 'Apache 2.0', + url: 'https://www.apache.org/licenses/LICENSE-2.0.html', + }); + + const parseResult = parse(context)(license); + expect(parseResult.length).to.equal(1); + const link = parseResult.get(0); + + expect(link).to.be.instanceof(Link); + expect(link.relation.toValue()).to.equal('license'); + expect(link.title.toValue()).to.equal('Apache 2.0'); + expect(link.href.toValue()).to.equal('https://www.apache.org/licenses/LICENSE-2.0.html'); + }); +});