├── .gitignore ├── .travis.yml ├── Changelog.md ├── Dockerfile ├── LICENSE ├── README.md ├── bin └── api-spec-converter ├── dist └── api-spec-converter.js ├── docs ├── 3rdpartylicenses.txt ├── favicon.png ├── fontawesome-webfont.674f50d287a8c48dc19b.eot ├── fontawesome-webfont.912ec66d7572ff821749.svg ├── fontawesome-webfont.af7ae505a9eed503f8b8.woff2 ├── fontawesome-webfont.b06871f281fee6b241d6.ttf ├── fontawesome-webfont.fee66e712a8a08eef580.woff ├── glyphicons-halflings-regular.448c34a56d699c29117a.woff2 ├── glyphicons-halflings-regular.89889688147bd7575d63.svg ├── glyphicons-halflings-regular.e18bbf611f2a2e43afc0.ttf ├── glyphicons-halflings-regular.f4769f9bdb7466be6508.eot ├── glyphicons-halflings-regular.fa2772327f55d8198301.woff ├── index.html ├── inline.31e1fb380eb7cf3d75b1.bundle.js ├── main.d654bbffa9baa2ba6f7c.bundle.js ├── polyfills.a30f833f6d1be4577636.bundle.js ├── scripts.2948e487a198f6dd77e0.bundle.js ├── styles.191000009f9cbee82244.bundle.css └── vendor.500811b651838c82aa2c.bundle.js ├── documentation ├── AddingFormats.md └── Contributing.md ├── index.js ├── karma.conf.js ├── lib ├── base_format.js ├── converters │ └── openapi3_to_swagger2.js ├── formats.js ├── formats │ ├── api_blueprint.js │ ├── google.js │ ├── io_docs.js │ ├── openapi_3.js │ ├── raml.js │ ├── swagger_1.js │ ├── swagger_2.js │ └── wadl.js └── util.js ├── package-lock.json ├── package.json ├── test ├── convert.js ├── input │ ├── api_blueprint │ │ ├── parameters.md │ │ ├── polls_api.md │ │ └── simplest.md │ ├── google │ │ └── youtube.json │ ├── io_docs │ │ ├── egnyte.json │ │ ├── foursquare.json │ │ ├── klout.json │ │ └── usatoday.json │ ├── openapi_3 │ │ ├── common_params.json │ │ ├── deprecated.yml │ │ ├── external_ref.json │ │ ├── external_ref_fragment.json │ │ ├── form_param.yml │ │ ├── has_external_ref.json │ │ ├── minimal.json │ │ ├── multiple_ref.yml │ │ ├── nested_oneof.yml │ │ ├── nullable.yml │ │ ├── param_schema_ref.yml │ │ ├── petstore.json │ │ ├── produces.yml │ │ ├── request_response_ref.yml │ │ ├── servers.yml │ │ ├── slash_ref.yml │ │ ├── yaml_ref.yml │ │ └── yaml_with_ref.yml │ ├── raml │ │ └── XKCD │ │ │ ├── api.raml │ │ │ ├── docs │ │ │ └── headline.md │ │ │ ├── examples │ │ │ └── comic-example.json │ │ │ └── schemas │ │ │ └── comic-schema.json │ ├── swagger_1 │ │ └── petstore │ │ │ ├── index.json │ │ │ ├── pet.json │ │ │ ├── store.json │ │ │ └── user.json │ ├── swagger_2 │ │ └── petstore.json │ └── wadl │ │ ├── OpenStack_example.wadl │ │ ├── facebook.xml │ │ ├── regex_paths.wadl │ │ └── sample_wadl.wadl ├── output │ ├── openapi_3 │ │ ├── OpenStack_example.json │ │ ├── XKCD.json │ │ ├── egnyte.json │ │ ├── facebook.json │ │ ├── foursquare.json │ │ ├── klout.json │ │ ├── parameters.json │ │ ├── petstore.json │ │ ├── petstore2.json │ │ ├── petstore_from_oas3.json │ │ ├── polls.json │ │ ├── regex_paths.json │ │ ├── sample_wadl.json │ │ ├── simplest.json │ │ ├── usatoday.json │ │ └── youtube.json │ └── swagger_2 │ │ ├── OpenStack_example.json │ │ ├── XKCD.json │ │ ├── common_params.json │ │ ├── deprecated.yml │ │ ├── egnyte.json │ │ ├── facebook.json │ │ ├── form_param.yml │ │ ├── foursquare.json │ │ ├── has_external_ref.json │ │ ├── klout.json │ │ ├── minimal.json │ │ ├── multiple_ref.json │ │ ├── nested_oneof.yml │ │ ├── nullable.yml │ │ ├── param_schema_ref.json │ │ ├── param_schema_unordered_ref.json │ │ ├── parameters.json │ │ ├── petstore-oa.yaml │ │ ├── petstore.json │ │ ├── petstore.yaml │ │ ├── petstore_from_oas3.json │ │ ├── polls.json │ │ ├── produces.json │ │ ├── regex_paths.json │ │ ├── request_response_ref.yml │ │ ├── sample_wadl.json │ │ ├── servers.json │ │ ├── simplest.json │ │ ├── slash_ref.json │ │ ├── usatoday.json │ │ ├── yaml_with_ref.yml │ │ └── youtube.json ├── setup │ ├── browser.js │ └── node.js └── test-cases.js └── web ├── .angular-cli.json ├── .gitignore ├── README.md ├── docs ├── 3rdpartylicenses.txt ├── favicon.ico ├── fontawesome-webfont.674f50d287a8c48dc19b.eot ├── fontawesome-webfont.912ec66d7572ff821749.svg ├── fontawesome-webfont.af7ae505a9eed503f8b8.woff2 ├── fontawesome-webfont.b06871f281fee6b241d6.ttf ├── fontawesome-webfont.fee66e712a8a08eef580.woff ├── glyphicons-halflings-regular.448c34a56d699c29117a.woff2 ├── glyphicons-halflings-regular.89889688147bd7575d63.svg ├── glyphicons-halflings-regular.e18bbf611f2a2e43afc0.ttf ├── glyphicons-halflings-regular.f4769f9bdb7466be6508.eot ├── glyphicons-halflings-regular.fa2772327f55d8198301.woff ├── index.html ├── inline.4f2476beaacd439998a5.bundle.js ├── main.0e55701e69e37474e126.bundle.js ├── polyfills.c95f56911f1080bda7b0.bundle.js ├── scripts.da6de8bbb6199d9ca04b.bundle.js ├── styles.782702e99e36e25410ad.bundle.css └── vendor.c6ecc421af1d4aa3d4e7.bundle.js ├── package-lock.json ├── package.json ├── prerender.ts ├── scripts ├── compare-versions.js └── new-component.js ├── server.ts ├── src ├── app │ ├── app.component.ts │ ├── app.module.ts │ ├── app.server.module.ts │ ├── home │ │ ├── home.component.ts │ │ └── home.pug │ ├── readme │ │ ├── readme.component.ts │ │ └── readme.pug │ ├── services │ │ └── platform.service.ts │ ├── spec-converter │ │ ├── spec-converter.component.ts │ │ └── spec-converter.pug │ └── styles │ │ ├── _variables.scss │ │ ├── app.scss │ │ └── styles.scss ├── assets │ └── .gitkeep ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon.png ├── index.html ├── main.server.ts ├── main.ts ├── polyfills.ts ├── tsconfig.app.json └── tsconfig.server.json ├── static.paths.js ├── tsconfig.json ├── webpack.cli-additions.js ├── webpack.server.config.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "node" 4 | deploy: 5 | provider: npm 6 | email: ivan.goncharov.ua@gmail.com 7 | api_key: 8 | secure: OjOXs0W+H6Cl5Avi/8gyYL1MklIoiaiOkomx+d+hokENuW31IHZKVYGJN92otqlFmwM27hpOtJ1kjdUSw1ZX6n6yB74INDXVsJ2GBtXpDm2KY/7P9wmW3Qw03nx4i4P/UGtmsh9ie6NF3w3+RZGX6w3CyGA3gafiZnVaiRzIZaeHvkgT5rdrIiWH2+VJOvyKfWNqrKj+BvpEdqvXhr/ZsjBNHlFewU2JeM9iNBR7A24+s+lI9Y2W7JGops6PjnQDidY03pIk+S5fzYFWMsdT+X0cQQBl8EopeubG4R5hZFqPP4OvezKhW3M29Er0AuJkogvxl7KneN12pHw1SPivbkdM/5zNseXwoJ5YvcJPbmMKJnthd8P+c5cOxIAT4KcQ6AemfhhVK8EakJD++l56gtkwRu8QpkcenCRYrKX29C3MWVxfNaLD7IqnU+4gh/PhbLjuIofQUQmNz+aG0bQ1LAItzGzNsit/TOGiKmwO5/dY8EJPiaQMtjzac/zc/zMBDP9P97sozPsP5X+R6TVVutkVAFTk4RXF86qiPYCP322Hq+eMPLT5BgJ7+auJZtEP6+BHHHO7Fyn8kUpMpwzucSoLjoNas516jl1FuRtfMQsohaP1s8x6JI8tLJQ7dkS7hXx58LTKTcA7EZRzmJnQH+UL7LsDgHS7rspAc2byU8U= 9 | on: 10 | tags: true 11 | repo: lucybot/api-spec-converter 12 | -------------------------------------------------------------------------------- /Changelog.md: -------------------------------------------------------------------------------- 1 | # 2016-07-11 2 | ## Released 2.0.0 to npm 3 | - Support for promises 4 | - Support of API blueprint in browser build 5 | 6 | ## Release 2.0.1 to npm and bower 7 | - Update README to describe support for promises 8 | 9 | # 2017-07-17 10 | ## Release 2.3.0 to npm 11 | - Support for YAML output 12 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node 2 | ADD . api-spec-converter/ 3 | RUN cd api-spec-converter && npm install 4 | RUN npm i -g ./api-spec-converter 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | (MIT License) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | 'Software'), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /bin/api-spec-converter: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict'; 3 | 4 | var _ = require('lodash'); 5 | 6 | var Program = require('commander'); 7 | var Package = require(__dirname + '/../package.json'); 8 | var Converter = require('..'); 9 | 10 | function keyValue (keyvalue, result) { 11 | const pair = keyvalue.split('=', 2); 12 | const key = pair[0]; 13 | const value = JSON.parse(pair[1]); 14 | result[key] = value; 15 | return result; 16 | } 17 | 18 | Program 19 | .version(Package.version) 20 | .description('Convert API descriptions between popular formats.\n\n ' + 21 | 'Supported formats: \n * ' + 22 | _(Converter.Formats).keys().join('\n * ') 23 | ) 24 | .option('-f, --from ', 'Specifies format to convert') 25 | .option('-t, --to ', 'Specifies output format') 26 | .option('-s, --syntax [outputSyntax]', 'Specifies output data syntax: json or yaml') 27 | .option('-o, --order [sortOrder]', 'Specifies top fields ordering: alpha or default openapi') 28 | .option('-c, --check', 'Check if result is valid spec') 29 | .option('-d, --dummy', 'Fill missing required fields with dummy data') 30 | .option('--passthrough ', 'Pass an option to the underlying converter', keyValue, {}) 31 | .arguments('') 32 | .action(main) 33 | .parse(process.argv); 34 | 35 | function main(url, options) { 36 | if (!options.from) 37 | Program.help(); 38 | 39 | if (!options.to) 40 | options.to = options.from; 41 | Converter.convert({ 42 | source: url, 43 | from: options.from, 44 | to: options.to, 45 | passthrough: options.passthrough 46 | }).then(function (spec) { 47 | console.log(spec.stringify({syntax: options.syntax, order: options.order})) 48 | if (!options.check) 49 | return; 50 | return spec.validate() 51 | .then(function (result) { 52 | if (result.errors) { 53 | process.exitCode = 255; 54 | console.error('\nErrors:\n'); 55 | console.error(JSON.stringify(result.errors, null, 2)); 56 | } 57 | if (result.warnings) { 58 | console.error('\nWarnings:\n'); 59 | console.error(JSON.stringify(result.warnings, null, 2)); 60 | } 61 | }); 62 | }).done(); 63 | } 64 | -------------------------------------------------------------------------------- /docs/3rdpartylicenses.txt: -------------------------------------------------------------------------------- 1 | core-js@2.6.11 2 | MIT 3 | Copyright (c) 2014-2019 Denis Pushkarev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | babel-polyfill@6.26.0 24 | MIT 25 | MIT 26 | 27 | zone.js@0.8.29 28 | MIT 29 | The MIT License 30 | 31 | Copyright (c) 2016-2018 Google, Inc. 32 | 33 | Permission is hereby granted, free of charge, to any person obtaining a copy 34 | of this software and associated documentation files (the "Software"), to deal 35 | in the Software without restriction, including without limitation the rights 36 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 37 | copies of the Software, and to permit persons to whom the Software is 38 | furnished to do so, subject to the following conditions: 39 | 40 | The above copyright notice and this permission notice shall be included in 41 | all copies or substantial portions of the Software. 42 | 43 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 44 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 45 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 46 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 47 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 48 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 49 | THE SOFTWARE. 50 | 51 | webpack@3.11.0 52 | MIT 53 | Copyright JS Foundation and other contributors 54 | 55 | Permission is hereby granted, free of charge, to any person obtaining 56 | a copy of this software and associated documentation files (the 57 | 'Software'), to deal in the Software without restriction, including 58 | without limitation the rights to use, copy, modify, merge, publish, 59 | distribute, sublicense, and/or sell copies of the Software, and to 60 | permit persons to whom the Software is furnished to do so, subject to 61 | the following conditions: 62 | 63 | The above copyright notice and this permission notice shall be 64 | included in all copies or substantial portions of the Software. 65 | 66 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 67 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 68 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 69 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 70 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 71 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 72 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 73 | 74 | bootstrap-sass@3.4.1 75 | MIT 76 | The MIT License (MIT) 77 | 78 | Copyright (c) 2011-2016 Twitter, Inc 79 | Copyright (c) 2011-2016 The Bootstrap Authors 80 | 81 | Permission is hereby granted, free of charge, to any person obtaining a copy 82 | of this software and associated documentation files (the "Software"), to deal 83 | in the Software without restriction, including without limitation the rights 84 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 85 | copies of the Software, and to permit persons to whom the Software is 86 | furnished to do so, subject to the following conditions: 87 | 88 | The above copyright notice and this permission notice shall be included in 89 | all copies or substantial portions of the Software. 90 | 91 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 92 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 93 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 94 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 95 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 96 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 97 | THE SOFTWARE. 98 | 99 | @angular/core@4.4.7 100 | MIT 101 | MIT 102 | 103 | @angular/platform-browser@4.4.7 104 | MIT 105 | MIT 106 | 107 | @angular/router@4.4.7 108 | MIT 109 | MIT 110 | 111 | @angular/forms@4.4.7 112 | MIT 113 | MIT 114 | 115 | @angular/http@4.4.7 116 | MIT 117 | MIT 118 | 119 | @angular/common@4.4.7 120 | MIT 121 | MIT 122 | 123 | file-saver@1.3.8 124 | MIT 125 | The MIT License 126 | 127 | Copyright © 2016 [Eli Grey][1]. 128 | 129 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 130 | 131 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 132 | 133 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 134 | 135 | [1]: http://eligrey.com 136 | 137 | @angular/platform-browser-dynamic@4.4.7 138 | MIT 139 | MIT -------------------------------------------------------------------------------- /docs/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucyBot-Inc/api-spec-converter/f51ac3660533835b2e6e424ec4356375112433b2/docs/favicon.png -------------------------------------------------------------------------------- /docs/fontawesome-webfont.674f50d287a8c48dc19b.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucyBot-Inc/api-spec-converter/f51ac3660533835b2e6e424ec4356375112433b2/docs/fontawesome-webfont.674f50d287a8c48dc19b.eot -------------------------------------------------------------------------------- /docs/fontawesome-webfont.af7ae505a9eed503f8b8.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucyBot-Inc/api-spec-converter/f51ac3660533835b2e6e424ec4356375112433b2/docs/fontawesome-webfont.af7ae505a9eed503f8b8.woff2 -------------------------------------------------------------------------------- /docs/fontawesome-webfont.b06871f281fee6b241d6.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucyBot-Inc/api-spec-converter/f51ac3660533835b2e6e424ec4356375112433b2/docs/fontawesome-webfont.b06871f281fee6b241d6.ttf -------------------------------------------------------------------------------- /docs/fontawesome-webfont.fee66e712a8a08eef580.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucyBot-Inc/api-spec-converter/f51ac3660533835b2e6e424ec4356375112433b2/docs/fontawesome-webfont.fee66e712a8a08eef580.woff -------------------------------------------------------------------------------- /docs/glyphicons-halflings-regular.448c34a56d699c29117a.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucyBot-Inc/api-spec-converter/f51ac3660533835b2e6e424ec4356375112433b2/docs/glyphicons-halflings-regular.448c34a56d699c29117a.woff2 -------------------------------------------------------------------------------- /docs/glyphicons-halflings-regular.e18bbf611f2a2e43afc0.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucyBot-Inc/api-spec-converter/f51ac3660533835b2e6e424ec4356375112433b2/docs/glyphicons-halflings-regular.e18bbf611f2a2e43afc0.ttf -------------------------------------------------------------------------------- /docs/glyphicons-halflings-regular.f4769f9bdb7466be6508.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucyBot-Inc/api-spec-converter/f51ac3660533835b2e6e424ec4356375112433b2/docs/glyphicons-halflings-regular.f4769f9bdb7466be6508.eot -------------------------------------------------------------------------------- /docs/glyphicons-halflings-regular.fa2772327f55d8198301.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucyBot-Inc/api-spec-converter/f51ac3660533835b2e6e424ec4356375112433b2/docs/glyphicons-halflings-regular.fa2772327f55d8198301.woff -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | API Spec Converter 21 |
22 |

API Spec Converter

The goal of this project is to allow REST API developers to convert between different 23 | API definition formats. 24 | This prevents lock-in, and allows developers to take advantage 25 | of tools that only support particular formats.

Currently, we only support converting from various formats (e.g. RAML and WADL) to Open API 2.0 (fka Swagger). 26 | Open API 3.0 and API Blueprint are not supported in this web app, but are supported using the 27 | command line tool.

Our plan is to eventually support conversion between any two formats. If you'd like to contribute, you can 28 | check out the open source library on GitHub.

29 |
30 |
-------------------------------------------------------------------------------- /docs/inline.31e1fb380eb7cf3d75b1.bundle.js: -------------------------------------------------------------------------------- 1 | !function(r){var n=window.webpackJsonp;window.webpackJsonp=function(e,u,c){for(var f,i,p,a=0,l=[];a swagger_2 conversion, inside `./lib/types/swagger_1.js`: 62 | 63 | ```js 64 | var SwaggerConverter = require('swagger-converter'); 65 | var Swagger1 = module.exports = function() { 66 | Swagger1.super_.apply(this, arguments); 67 | this.type = 'swagger_1'; 68 | 69 | this.converters.swagger_2 = function(swagger1, callback) { 70 | try { 71 | var swagger2 = SwaggerConverter.convert(swagger1.spec, swagger1.subResources); 72 | 73 | if (swagger2.info.title === 'Title was not specified') 74 | swagger2.info.title = swagger2.host; 75 | } catch(e) { 76 | return callback(e); 77 | } 78 | return callback(null, swagger2); 79 | } 80 | } 81 | ``` 82 | 83 | ## Internal Types 84 | If you're adding your type inside this package, you should: 85 | * Write your type's logic in `./lib/types/.js` 86 | * Add your type to `./lib/types.js` 87 | * Update README.md 88 | 89 | where `` is an identifier for your type, e.g. swagger_2 or raml. 90 | 91 | ## External Types 92 | If you're adding a type from outside this repository (e.g. a proprietary type), you should: 93 | * Write your type's logic in `.js` inside your repository 94 | * Set `require('api-spec-converter').Types[""] = require('./.js') 95 | 96 | Then you can call `Converter.convert()` with `` just as you would with other format names. 97 | 98 | See [kaltura-spec-converter](https://github.com/bobby-brennan/kaltura-spec-converter/blob/master/index.js) for an example. 99 | -------------------------------------------------------------------------------- /documentation/Contributing.md: -------------------------------------------------------------------------------- 1 | Contributions are welcome and encouraged. We'll try to respond to pull requests within 24 hours. 2 | 3 | If you'd like to add a new format, see [AddingFormats.md](AddingFormats.md). 4 | 5 | ### Starter Projects 6 | * Naming inconsistency - Change "Type" to "Format" in both code and docs (Issue #75) 7 | * Clean up the [Demo UI](http://lucybot.github.io/api-spec-converter/) on the gh-pages branch 8 | * Add new tests for existing formats 9 | * Add copy/paste to Demo UI (Issue #46) 10 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var Promise = require('bluebird'); 5 | 6 | var Formats = require('./lib/formats.js'); 7 | var Util = require('./lib/util.js'); 8 | 9 | var Converter = module.exports = {}; 10 | Converter.Formats = Formats; 11 | Converter.BaseFormat = require('./lib/base_format.js'); 12 | Converter.ResourceReaders = Util.resourceReaders; 13 | 14 | Converter.getSpec = function (source, format, callback) { 15 | if (!Formats.hasOwnProperty(format)) { 16 | throw new Error('Unknow format ' + format + ', you might have forgotten installing an optional dependency'); 17 | } 18 | var spec = new Formats[format](); 19 | return spec.resolveResources(source) 20 | .return(spec) 21 | .asCallback(callback); 22 | } 23 | 24 | Converter.getFormatName = function (name, version) { 25 | var result; 26 | _.each(Formats, function (format, formatName) { 27 | format = format.prototype; 28 | if (format.formatName === name && format.supportedVersions.indexOf(version) !== -1) 29 | result = formatName; 30 | }); 31 | return result; 32 | }; 33 | 34 | Converter.convert = function(options, callback) { 35 | return Converter.getSpec(options.source, options.from) 36 | .then(fromSpec => fromSpec.convertTo(options.to, options.passthrough)) 37 | .asCallback(callback); 38 | } 39 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | process.env.CHROME_BIN = require('puppeteer').executablePath() 2 | console.log(process.env.CHROME_BIN); 3 | module.exports = function (config) { 4 | config.set({ 5 | browsers: ['ChromeHeadlessNoSandbox'], 6 | customLaunchers: { 7 | ChromeHeadlessNoSandbox: { 8 | base: 'ChromeHeadless', 9 | flags: ['--no-sandbox'] 10 | } 11 | }, 12 | frameworks: ['mocha', 'chai'], 13 | files: [ 14 | { pattern: 'node_modules/babel-polyfill/browser.js', instrument: false}, 15 | 'dist/api-spec-converter.js', 16 | 'test/setup/browser.js', 17 | 'test/test-cases.js', 18 | 'test/*.js', 19 | {pattern: 'test/input/**/*', included: false, watched: false, served: true}, 20 | {pattern: 'test/output/**/*', included: false, watched: false, served: true} 21 | ], 22 | 23 | proxies: { 24 | '/test/': '/base/test/' 25 | }, 26 | 27 | reporters: ['mocha'], 28 | 29 | browserNoActivityTimeout: 30000 30 | }); 31 | } 32 | -------------------------------------------------------------------------------- /lib/base_format.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var Promise = require('bluebird'); 5 | var SortObject = require('deep-sort-object'); 6 | var CompositeError = require('composite-error'); 7 | 8 | var Formats = require('./formats.js'); 9 | var Util = require('./util.js'); 10 | var Yaml = require('js-yaml'); 11 | 12 | var BaseFormat = module.exports = function(spec) { 13 | if (spec) this.spec = spec; 14 | this.format = "base_format"; 15 | this.converters = {}; 16 | } 17 | 18 | // An array containing the swagger top level attributes we want to enforce order on. 19 | // The attributes are listed in reverse order (swagger will be output first). 20 | // The sort function will order according to the index of the attributes in this array. 21 | // Attributes not found will have index -1 and will be sorted alphabetically 22 | // after the elements in this array. 23 | let attr = [ 24 | 'externalDocs', 25 | 'tags', 26 | 'security', 27 | 'securityDefinitions', 28 | 'responses', 29 | 'parameters', 30 | 'definitions', 31 | 'components', 32 | 'paths', 33 | 'produces', 34 | 'consumes', 35 | 'schemes', 36 | 'basePath', 37 | 'host', 38 | 'servers', 39 | 'info', 40 | 'swagger', 41 | 'openapi', 42 | ]; 43 | 44 | BaseFormat.prototype.stringify = function(options) { 45 | var syntax 46 | var order 47 | 48 | if (typeof options === "object") { 49 | syntax = options.syntax 50 | order = options.order 51 | } 52 | // set options to default values if not specified 53 | syntax = syntax || 'json'; // other value 'yaml' 54 | order = order || 'openapi'; // other value 'alpha' for a-z alphabetical order 55 | 56 | if (order == 'false') { 57 | sortedSpecs = this.spec 58 | } 59 | else { 60 | var sortedSpecs = SortObject(this.spec, function (a, b) { 61 | var aIdx = -1 62 | var bIdx = -1 63 | 64 | if (order != 'alpha') { 65 | // do index lookup only if it will be used; i.e. for OpenApi ordering 66 | aIdx = attr.indexOf(a) 67 | bIdx = attr.indexOf(b) 68 | } 69 | 70 | // if none of the args to compare are in the pre-sorted list 71 | // use the normal alphabetical sort 72 | if (aIdx == -1 && bIdx == -1) { 73 | //By default sort is done using local aware compare 74 | //Instead using order that will never change 75 | if (a === b) 76 | return 0; 77 | return (a < b) ? -1 : 1; 78 | } 79 | 80 | // sort according to index in attr pre-sorted list 81 | if (aIdx === bIdx) return 0; 82 | return aIdx < bIdx ? 1 : -1; 83 | }); 84 | } 85 | 86 | if (syntax == "yaml") { 87 | return Yaml.safeDump(sortedSpecs) 88 | } else { 89 | return JSON.stringify(sortedSpecs, null, 2); 90 | } 91 | } 92 | 93 | BaseFormat.prototype.parsers = []; 94 | BaseFormat.prototype.checkFormat = undefined; 95 | BaseFormat.prototype.fixSpec = function () {}; 96 | BaseFormat.prototype.fillMissing = undefined; 97 | BaseFormat.prototype.validate = function (callback) { 98 | return Promise.resolve({errors: null, warnings: null}) 99 | .asCallback(callback); 100 | }; 101 | 102 | BaseFormat.prototype.listSubResources = function () { 103 | return []; 104 | }; 105 | 106 | BaseFormat.prototype.resolveSubResources = function () { 107 | var sources = this.listSubResources(); 108 | 109 | return Promise.map(_.values(sources), url => this.readSpec(url), 110 | {concurrency: 5}) //Limit number of parallel downloads to 5 111 | .then(resources => { 112 | resources = _.map(resources, x => x[0]); 113 | var refs = _.keys(sources); 114 | this.subResources = _.zipObject(refs, resources); 115 | }); 116 | }; 117 | 118 | BaseFormat.prototype.parse = function (data) { 119 | if (!_.isString(data)) 120 | return Promise.resolve(data); 121 | 122 | return Promise.any(_.map(this.parsers, parser => parser(data))) 123 | .catch(Promise.AggregateError, err => { 124 | throw new CompositeError('Failed to parse spec', _.toArray(err)); 125 | }); 126 | } 127 | 128 | BaseFormat.prototype.readSpec = function (source) { 129 | var sourceType = Util.getSourceType(source); 130 | 131 | if (!sourceType) 132 | throw Error('Spec source should be object, string, URL or filename.'); 133 | 134 | return Util.resourceReaders[sourceType](source) 135 | .then(data => this.parse(data)) 136 | .then(spec => [spec, sourceType]); 137 | } 138 | 139 | BaseFormat.prototype.resolveResources = function(source) { 140 | return this.readSpec(source) 141 | .spread((spec, sourceType) => { 142 | if (!this.checkFormat(spec)) 143 | throw Error(sourceType + ' ' + source + ' is not valid ' + this.format); 144 | 145 | this.spec = spec; 146 | this.sourceType = sourceType; 147 | //Only URL and File name provide useful information 148 | if (sourceType === 'url' || sourceType === 'file') 149 | this.source = source; 150 | }) 151 | .then(() => this.resolveSubResources()) 152 | .then(() => { 153 | this.fixSpec(); 154 | 155 | var version = this.getFormatVersion(); 156 | if (this.supportedVersions.indexOf(version) === -1) 157 | throw Error('Unsupported version'); 158 | }); 159 | } 160 | 161 | BaseFormat.prototype.convertTo = function(format, passthrough, callback) { 162 | return Promise.try(() => { 163 | if (format === this.format) 164 | return Promise.resolve(this); 165 | 166 | var convert = this.converters[format]; 167 | if (!convert) 168 | throw Error(`Unable to convert from ${this.format} to ${format}`); 169 | 170 | return convert(this, passthrough) 171 | .then(spec => { 172 | spec = new Formats[format](spec); 173 | spec.fixSpec(); 174 | return spec; 175 | }, err => { 176 | err.message = 'Error during conversion: ' + err.message; 177 | throw err; 178 | }); 179 | }).asCallback(callback); 180 | } 181 | 182 | BaseFormat.prototype.convertTransitive = function(intermediaries, passthrough) { 183 | let prom = Promise.resolve(this); 184 | intermediaries.forEach(intermediary => { 185 | prom = prom.then(spec => { 186 | return spec.convertTo(intermediary, passthrough); 187 | }) 188 | }); 189 | return prom.then(spec => spec.spec); 190 | } 191 | -------------------------------------------------------------------------------- /lib/formats.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Formats = module.exports = {}; 4 | 5 | function ignoreModuleNodeFound(e) { 6 | if (e.code !== 'MODULE_NOT_FOUND') { 7 | throw e; 8 | } 9 | } 10 | 11 | // some modules do require optionalDependencies, we silently catch loading if 12 | // that does not work, and we will warn user when he will try using it 13 | try { 14 | Formats.swagger_1 = require('./formats/swagger_1.js'); 15 | } catch (e) { 16 | ignoreModuleNodeFound(e); 17 | } 18 | try { 19 | Formats.swagger_2 = require('./formats/swagger_2.js'); 20 | } catch (e) { 21 | ignoreModuleNodeFound(e); 22 | } 23 | try { 24 | Formats.openapi_3 = require('./formats/openapi_3.js'); 25 | } catch (e) { 26 | ignoreModuleNodeFound(e); 27 | } 28 | try { 29 | Formats.api_blueprint = require('./formats/api_blueprint.js'); 30 | } catch (e) { 31 | ignoreModuleNodeFound(e); 32 | } 33 | Formats.io_docs = require('./formats/io_docs.js'); 34 | try { 35 | Formats.google = require('./formats/google.js'); 36 | } catch (e) { 37 | ignoreModuleNodeFound(e); 38 | } 39 | try { 40 | Formats.raml = require('./formats/raml.js'); 41 | } catch (e) { 42 | ignoreModuleNodeFound(e); 43 | } 44 | Formats.wadl = require('./formats/wadl.js'); 45 | -------------------------------------------------------------------------------- /lib/formats/api_blueprint.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var Promise = require('bluebird'); 5 | var Drafter = require('drafter.js'); 6 | var Inherits = require('util').inherits; 7 | var BPToSwagger = require('apib2swagger'); 8 | 9 | var BaseFormat = require('../base_format.js'); 10 | 11 | var APIBlueprint = module.exports = function() { 12 | APIBlueprint.super_.apply(this, arguments); 13 | this.format = 'api_blueprint'; 14 | 15 | this.converters.swagger_2 = Promise.method(apibp => { 16 | return BPToSwagger.convertParsed(apibp.spec, {}); 17 | }); 18 | 19 | this.converters.openapi_3 = 20 | Promise.method(apibp => this.convertTransitive(['swagger_2', 'openapi_3'])); 21 | } 22 | 23 | Inherits(APIBlueprint, BaseFormat); 24 | 25 | APIBlueprint.prototype.formatName = 'apiBlueprint'; 26 | APIBlueprint.prototype.supportedVersions = ['1A']; 27 | APIBlueprint.prototype.getFormatVersion = function () { 28 | return _(this.spec.metadata).filter({name: 'FORMAT'}) 29 | .get('[0].value', '1A'); 30 | } 31 | 32 | APIBlueprint.prototype.parsers = { 33 | 'APIB': Promise.method(data => Drafter.parse(data, {type: 'ast'}).ast) 34 | }; 35 | 36 | APIBlueprint.prototype.checkFormat = function (spec) { 37 | //TODO: 'spec.ast' isn't working find other criteria. 38 | return true; 39 | } 40 | -------------------------------------------------------------------------------- /lib/formats/google.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Inherits = require('util').inherits; 4 | 5 | var Promise = require('bluebird'); 6 | var BaseFormat = require('../base_format.js'); 7 | var Util = require('../util.js'); 8 | var Google2Swagger = require('google-discovery-to-swagger'); 9 | 10 | var Google = module.exports = function() { 11 | Google.super_.apply(this, arguments); 12 | this.format = 'google'; 13 | 14 | this.converters.swagger_2 = 15 | Promise.method(google => Google2Swagger.convert(google.spec)); 16 | 17 | this.converters.openapi_3 = 18 | Promise.method(google => this.convertTransitive(['swagger_2', 'openapi_3'])); 19 | } 20 | 21 | Inherits(Google, BaseFormat); 22 | 23 | Google.prototype.formatName = 'google'; 24 | Google.prototype.supportedVersions = ['v1']; 25 | Google.prototype.getFormatVersion = function () { 26 | return Google2Swagger.getVersion(this.spec); 27 | } 28 | 29 | Google.prototype.parsers = { 30 | 'JSON': Util.parseJSON 31 | }; 32 | 33 | Google.prototype.checkFormat = function (spec) { 34 | return Google2Swagger.checkFormat(spec); 35 | } 36 | 37 | -------------------------------------------------------------------------------- /lib/formats/io_docs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Inherits = require('util').inherits; 4 | var Path = require('path'); 5 | var URL = require('url'); 6 | var _ = require('lodash'); 7 | var Promise = require('bluebird'); 8 | 9 | var BaseFormat = require('../base_format.js'); 10 | var Util = require('../util.js'); 11 | 12 | var IODocs = module.exports = function() { 13 | IODocs.super_.apply(this, arguments); 14 | this.type = 'io_docs'; 15 | this.converters.swagger_2 = 16 | Promise.method(iodocs => convertToSwagger(iodocs.spec)); 17 | 18 | this.converters.openapi_3 = 19 | Promise.method(iodocs => this.convertTransitive(['swagger_2', 'openapi_3'])); 20 | } 21 | 22 | Inherits(IODocs, BaseFormat); 23 | 24 | IODocs.prototype.formatName = 'ioDocs'; 25 | IODocs.prototype.supportedVersions = ['1.0']; 26 | IODocs.prototype.getFormatVersion = function () { 27 | //It's looks like format doesn't have versions, so treat it as '1.0' 28 | return '1.0'; 29 | } 30 | 31 | IODocs.prototype.parsers = { 32 | 'JSON': Util.parseJSON 33 | }; 34 | 35 | IODocs.prototype.checkFormat = function (spec) { 36 | return spec.protocol === 'rest'; 37 | } 38 | 39 | function convertToSwagger(iodocs) { 40 | var swagger = {swagger: '2.0'}; 41 | swagger.info = { 42 | description: iodocs.description, 43 | title: iodocs.name 44 | }; 45 | 46 | var baseURL = URL.parse(iodocs.basePath); 47 | swagger.schemes = [baseURL.protocol]; 48 | swagger.host = [baseURL.hostname]; 49 | swagger.basePath = Util.joinPath(baseURL.path || '', iodocs.publicPath || ''); 50 | swagger.definitions = iodocs.schemas; 51 | swagger.paths = {}; 52 | _.forIn(iodocs.resources, function(resource, name) { 53 | _.forIn(resource.methods, function(method, name) { 54 | swagger.paths[method.path] = swagger.paths[method.path] || {}; 55 | var route = swagger.paths[method.path][method.httpMethod.toLowerCase()] = {}; 56 | route.responses = {'200': {description: "success"}}; 57 | route.parameters = []; 58 | _.forIn(method.parameters, function(param, paramName) { 59 | var swaggerParam = { 60 | name: paramName, 61 | in: param.location || 'query', 62 | default: param.default, 63 | description: param.description, 64 | type: param.type, 65 | enum: param.enum, 66 | } 67 | if (swaggerParam.in === 'pathReplace') swaggerParam.in = 'path'; 68 | route.parameters.push(swaggerParam); 69 | }); 70 | }); 71 | }); 72 | 73 | return swagger; 74 | } 75 | -------------------------------------------------------------------------------- /lib/formats/openapi_3.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Inherits = require('util').inherits; 4 | 5 | var Promise = require('bluebird'); 6 | var _ = require('lodash'); 7 | var BaseFormat = require('../base_format.js'); 8 | var Util = require('../util.js'); 9 | var validator = require('swagger2openapi/validate.js'); 10 | var openapi2swagger = require('../converters/openapi3_to_swagger2.js'); 11 | 12 | var OpenApi3 = module.exports = function() { 13 | OpenApi3.super_.apply(this, arguments); 14 | this.format = 'openapi_3'; 15 | 16 | this.converters.swagger_2 = 17 | Promise.method(oa => { 18 | let converter = new openapi2swagger(oa); 19 | return converter.convert(); 20 | }); 21 | }; 22 | Inherits(OpenApi3, BaseFormat); 23 | 24 | OpenApi3.prototype.formatName = 'openapi'; 25 | OpenApi3.prototype.supportedVersions = ['3.0']; 26 | OpenApi3.prototype.getFormatVersion = function () { 27 | var versionComponents = this.spec.openapi.split('.'); 28 | return versionComponents[0]+'.'+versionComponents[1]; 29 | }; 30 | 31 | OpenApi3.prototype.fillMissing = function (dummyData) { 32 | dummyData = dummyData || { 33 | info: { 34 | title: '< An API title here >', 35 | version: '< An API version here >' 36 | } 37 | }; 38 | 39 | this.spec = _.merge(dummyData, this.spec); 40 | }; 41 | 42 | OpenApi3.prototype.parsers = { 43 | 'JSON': Util.parseJSON, 44 | 'YAML': Util.parseYAML 45 | }; 46 | 47 | OpenApi3.prototype.checkFormat = function (spec) { 48 | return !_.isUndefined(spec.openapi); 49 | }; 50 | 51 | OpenApi3.prototype.validate = function (callback) { 52 | var openapi = this.spec; 53 | var promise = new Promise(function(resolve,reject){ 54 | var result = {}; 55 | try { 56 | result = validator.validateSync(openapi,result,function(err,options){ 57 | }); 58 | } 59 | catch (ex) { 60 | result.errors = {message: ex.message, context: result.context}; 61 | } 62 | resolve(result); 63 | }); 64 | return Promise.resolve(promise).asCallback(callback); 65 | }; 66 | 67 | -------------------------------------------------------------------------------- /lib/formats/raml.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var RamlParser = require('raml-parser'); 5 | var Raml2Swagger = require('raml-to-swagger'); 6 | var Inherits = require('util').inherits; 7 | var Promise = require('bluebird'); 8 | 9 | var BaseFormat = require('../base_format.js'); 10 | var Util = require('../util.js'); 11 | 12 | var Raml = module.exports = function() { 13 | Raml.super_.apply(this, arguments); 14 | this.format = 'raml'; 15 | 16 | this.converters.swagger_2 = 17 | Promise.method(raml => Raml2Swagger.convert(raml.spec)); 18 | 19 | this.converters.openapi_3 = 20 | Promise.method(raml => this.convertTransitive(['swagger_2', 'openapi_3'])); 21 | } 22 | 23 | Inherits(Raml, BaseFormat); 24 | 25 | Raml.prototype.formatName = 'raml'; 26 | Raml.prototype.supportedVersions = ['0.8']; 27 | Raml.prototype.getFormatVersion = function () { 28 | return '0.8'; 29 | } 30 | 31 | Raml.prototype.readSpec = function (source) { 32 | var sourceType = Util.getSourceType(source); 33 | 34 | return Promise.try(() => { 35 | if (sourceType === 'url' || sourceType === 'file') 36 | return RamlParser.loadFile(source) 37 | else 38 | return RamlParser.load(source) 39 | }) 40 | .then(spec => [spec, sourceType]); 41 | } 42 | 43 | Raml.prototype.checkFormat = function (spec) { 44 | return true; 45 | } 46 | -------------------------------------------------------------------------------- /lib/formats/swagger_1.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var Path = require('path'); 5 | 6 | var Promise = require('bluebird'); 7 | var Inherits = require('util').inherits; 8 | var URI = require('urijs'); 9 | var SwaggerConverter = require('swagger-converter'); 10 | 11 | var BaseFormat = require('../base_format.js'); 12 | var Util = require('../util.js'); 13 | 14 | var Swagger1 = module.exports = function() { 15 | Swagger1.super_.apply(this, arguments); 16 | this.format = 'swagger_1'; 17 | 18 | this.converters.swagger_2 = Promise.method((swagger1, passthrough) => { 19 | passthrough = passthrough || {}; 20 | passthrough.buildTagsFromPaths = passthrough.buildTagsFromPaths !== false; 21 | var swagger2 = SwaggerConverter.convert( 22 | swagger1.spec, 23 | swagger1.subResources, 24 | passthrough 25 | ); 26 | 27 | if (swagger2.info.title === 'Title was not specified') 28 | swagger2.info.title = swagger2.host; 29 | return swagger2; 30 | }); 31 | 32 | this.converters.openapi_3 = 33 | Promise.method((swagger1, passthrough) => this.convertTransitive(['swagger_2', 'openapi_3'], passthrough)); 34 | } 35 | 36 | Inherits(Swagger1, BaseFormat); 37 | 38 | Swagger1.prototype.formatName = 'swagger'; 39 | Swagger1.prototype.supportedVersions = ['1.0', '1.1', '1.2']; 40 | Swagger1.prototype.getFormatVersion = function () { 41 | return this.spec.swaggerVersion; 42 | } 43 | 44 | Swagger1.prototype.parsers = { 45 | 'JSON': Util.parseJSON 46 | }; 47 | 48 | Swagger1.prototype.checkFormat = function (spec) { 49 | return !_.isUndefined(spec.swaggerVersion); 50 | } 51 | 52 | Swagger1.prototype.fixSpec = function () { 53 | if (this.sourceType == 'url') { 54 | var url = URI(this.source); 55 | 56 | if (!this.spec.basePath) 57 | this.spec.basePath = url.filename('').href(); 58 | else { 59 | var basePath = URI(this.spec.basePath); 60 | basePath.scheme(basePath.scheme() || url.scheme()); 61 | basePath.host(basePath.host() || url.host()); 62 | this.spec.basePath = basePath.href(); 63 | } 64 | } 65 | }; 66 | 67 | Swagger1.prototype.listSubResources = function () { 68 | return SwaggerConverter.listApiDeclarations(this.source, this.spec); 69 | }; 70 | -------------------------------------------------------------------------------- /lib/formats/swagger_2.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var Inherits = require('util').inherits; 5 | var URI = require('urijs'); 6 | var sway = require('sway'); 7 | var Promise = require('bluebird'); 8 | var swagger2openapi = require('swagger2openapi'); 9 | 10 | var BaseFormat = require('../base_format.js'); 11 | var Util = require('../util.js'); 12 | 13 | var Swagger2 = module.exports = function() { 14 | Swagger2.super_.apply(this, arguments); 15 | this.format = 'swagger_2'; 16 | this.converters.openapi_3 = Promise.method(swagger => swagger2openapi.convert(swagger.spec,{direct:true,patch:true})); 17 | } 18 | 19 | Inherits(Swagger2, BaseFormat); 20 | 21 | Swagger2.prototype.formatName = 'swagger'; 22 | Swagger2.prototype.supportedVersions = ['2.0']; 23 | Swagger2.prototype.getFormatVersion = function () { 24 | return this.spec.swagger; 25 | } 26 | 27 | Swagger2.prototype.fixSpec = function () { 28 | var swagger = this.spec; 29 | 30 | //Typical mistake is to make version number insted of string 31 | var version = _.get(swagger, 'info.version'); 32 | if (_.isNumber(version)) 33 | swagger.info.version = version % 1 ? version.toString() : version.toFixed(1); 34 | 35 | if (this.sourceType == 'url') { 36 | var url = URI(this.source); 37 | swagger.host = swagger.host || url.host(); 38 | swagger.schemes = swagger.schemes || [url.scheme()]; 39 | //TODO: decide what to do with base path 40 | } 41 | 42 | Util.removeNonValues(swagger); 43 | 44 | var basePath = swagger.basePath 45 | if (_.isString(basePath)) 46 | swagger.basePath = URI().path(basePath).normalize().path(); 47 | 48 | _.each(swagger.definitions, function (schema) { 49 | if (!_.isUndefined(schema.id)) 50 | delete schema.id; 51 | }); 52 | }; 53 | 54 | Swagger2.prototype.fillMissing = function (dummyData) { 55 | dummyData = dummyData || { 56 | info: { 57 | title: '< An API title here >', 58 | version: '< An API version here >' 59 | } 60 | }; 61 | 62 | this.spec = _.merge(dummyData, this.spec); 63 | } 64 | 65 | Swagger2.prototype.parsers = { 66 | 'JSON': Util.parseJSON, 67 | 'YAML': Util.parseYAML 68 | }; 69 | 70 | Swagger2.prototype.checkFormat = function (spec) { 71 | return !_.isUndefined(spec.swagger); 72 | } 73 | 74 | Swagger2.prototype.validate = function (callback) { 75 | var promise = sway.create({definition: this.spec, jsonRefs: this.jsonRefs}) 76 | .then(function (swaggerObj) { 77 | var result = swaggerObj.validate(); 78 | 79 | result.remotesResolved = swaggerObj.definitionRemotesResolved; 80 | 81 | if (_.isEmpty(result.errors)) 82 | result.errors = null; 83 | if (_.isEmpty(result.warnings)) 84 | result.warnings = null; 85 | return result; 86 | }); 87 | return Promise.resolve(promise).asCallback(callback); 88 | }; 89 | -------------------------------------------------------------------------------- /lib/util.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var FS = require('fs'); 4 | var Path = require('path'); 5 | 6 | var _ = require('lodash'); 7 | var URI = require('urijs'); 8 | var YAML = require('js-yaml'); 9 | var Promise = require('bluebird'); 10 | var traverse = require('traverse'); 11 | var Request = Promise.promisify(require('request'), {multiArgs: true}); 12 | 13 | module.exports.joinPath = function () { 14 | var argArray = Array.prototype.slice.call(arguments); 15 | return argArray.join('/').replace(/\/\/+/g, '/') 16 | } 17 | 18 | module.exports.parseJSON = Promise.method(JSON.parse); 19 | module.exports.parseYAML = Promise.method(YAML.safeLoad); 20 | 21 | function readUrl(url, callback) { 22 | var options = { 23 | uri: url, 24 | headers: { 25 | //TODO: allow different fomrats to define different MIME types. 26 | 'Accept': 'application/json,*/*', 27 | } 28 | }; 29 | 30 | return Request(options) 31 | .spread((response, data) => { 32 | if (response.statusCode !== 200) 33 | throw Error(`Can not GET ${url}: ` + response.statusMessage); 34 | return data; 35 | }); 36 | } 37 | 38 | function readFile(filename) { 39 | return Promise.fromCallback(callback => { 40 | FS.readFile(filename, 'utf8', callback); 41 | }); 42 | } 43 | 44 | function readDummy(data) { 45 | return Promise.resolve(data); 46 | } 47 | 48 | module.exports.resourceReaders = { 49 | url: readUrl, 50 | file: readFile, 51 | object: readDummy, 52 | string: readDummy, 53 | }; 54 | 55 | module.exports.getSourceType = function (source) { 56 | if (_.isObject(source)) 57 | return 'object'; 58 | if (!_.isString(source)) 59 | return undefined; 60 | 61 | // windows resolved paths look like absolute URLs, 62 | // so check for file existence. 63 | try { 64 | // FIXME: existsSync fails in browser 65 | if (FS.existsSync(source)) return 'file'; 66 | } catch (e) {} 67 | 68 | var uri = new URI(source); 69 | if (uri.is('absolute')) 70 | return 'url'; 71 | else if (uri.is('relative')) 72 | return 'file'; 73 | else 74 | return 'string'; 75 | }; 76 | 77 | module.exports.removeNonValues = function (obj) { 78 | traverse(obj).forEach(function (value) { 79 | if (value === undefined) 80 | this.remove(); 81 | }); 82 | } 83 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "api-spec-converter", 3 | "version": "2.12.0", 4 | "engines": { 5 | "node": ">=6.0.0" 6 | }, 7 | "description": "Convert API descriptions between popular formats such as OpenAPI(fka Swagger), RAML, API Blueprint, WADL, etc.", 8 | "main": "index.js", 9 | "scripts": { 10 | "browserify": "node node_modules/mkdirp/bin/cmd dist && browserify -s APISpecConverter -o dist/api-spec-converter.js .", 11 | "test": "mocha && npm run browserify && karma start --single-run && git checkout -- dist" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/lucybot/api-spec-converter.git" 16 | }, 17 | "keywords": [ 18 | "API", 19 | "REST", 20 | "Restful", 21 | "convert", 22 | "converter", 23 | "OpenAPI", 24 | "OpenAPI Specification", 25 | "Swagger", 26 | "RAML", 27 | "Blueprint", 28 | "API Blueprint", 29 | "GoogleDiscovery", 30 | "WADL", 31 | "I/O Docs" 32 | ], 33 | "contributors": [ 34 | "Bobby Brennan (https://lucybot.com)", 35 | "Ivan Goncharov (http://apis.guru)" 36 | ], 37 | "license": "MIT", 38 | "bugs": { 39 | "url": "https://github.com/lucybot/api-spec-converter/issues" 40 | }, 41 | "homepage": "https://github.com/lucybot/api-spec-converter", 42 | "bin": { 43 | "api-spec-converter": "./bin/api-spec-converter" 44 | }, 45 | "browserify": { 46 | "transform": [ 47 | [ 48 | "babelify", 49 | { 50 | "presets": [ 51 | "env" 52 | ] 53 | } 54 | ] 55 | ] 56 | }, 57 | "dependencies": { 58 | "bluebird": "^3.7.2", 59 | "commander": "^2.20.0", 60 | "composite-error": "^0.1.1", 61 | "deep-sort-object": "^1.0.2", 62 | "js-yaml": "^3.14.0", 63 | "lodash": "^4.17.19", 64 | "lodash.clonedeep": "^4.5.0", 65 | "request": "^2.88.2", 66 | "source-map": "0.6.0", 67 | "sway": "^2.0.5", 68 | "traverse": "^0.6.6", 69 | "urijs": "^1.19.5", 70 | "xml2js": "^0.4.23" 71 | }, 72 | "devDependencies": { 73 | "babel-polyfill": "^6.23.0", 74 | "babel-preset-env": "^1.7.0", 75 | "babel-preset-es2015": "^6.24.1", 76 | "babelify": "^7.3.0", 77 | "browserify": "^16.5.1", 78 | "chai": "^3.5.0", 79 | "karma": "^5.1.0", 80 | "karma-chai-plugins": "^0.7.0", 81 | "karma-chrome-launcher": "^2.2.0", 82 | "karma-mocha": "^2.0.1", 83 | "karma-mocha-reporter": "^2.2.3", 84 | "karma-phantomjs-launcher": "^1.0.4", 85 | "mkdirp": "^0.5.1", 86 | "mocha": "^8.1.2", 87 | "puppeteer": "^1.20.0" 88 | }, 89 | "optionalDependencies": { 90 | "apib2swagger": "^1.9.0", 91 | "drafter.js": "^2.6.7", 92 | "google-discovery-to-swagger": "^2.0.0", 93 | "raml-parser": "^0.8.18", 94 | "raml-to-swagger": "^1.1.0", 95 | "swagger-converter": "^1.5.1", 96 | "swagger2openapi": "2.9.*" 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /test/convert.js: -------------------------------------------------------------------------------- 1 | var isBrowser = typeof window === 'object'; 2 | 3 | if (!isBrowser) { 4 | require('./setup/node'); 5 | } 6 | 7 | function convertFile(testCase) { 8 | var infile = getFileName('input', testCase.in); 9 | return Converter.convert({ 10 | from: testCase.in.format, 11 | to: testCase.out.format, 12 | source: infile, 13 | }) 14 | .then(function (spec) { 15 | spec.fillMissing(); 16 | return spec; 17 | }); 18 | } 19 | 20 | describe('Converter', function() { 21 | this.timeout(10000); 22 | TestCases.forEach(function(testCase) { 23 | if (isBrowser && testCase.skipBrowser) return; 24 | var testName = 'should convert ' + testCase.in.file + 25 | ' from ' + testCase.in.format + ' to ' + testCase.out.format; 26 | it(testName, function(done) { 27 | convertFile(testCase) 28 | .then(function(spec) { 29 | var outfile = getFileName('output', testCase.out); 30 | var order = testCase.out.order || 'alpha'; 31 | if (WRITE_GOLDEN) 32 | FS.writeFileSync(outfile, spec.stringify({order: order, syntax: testCase.out.syntax}) + '\n'); 33 | 34 | getFile(outfile, function(err, golden) { 35 | try { 36 | expect(spec.spec).to.deep.equal(golden); 37 | } catch(e) { 38 | return done(e); 39 | } 40 | done(); 41 | }); 42 | }) 43 | .catch(function (e) { 44 | done(e); 45 | }); 46 | }) 47 | }) 48 | 49 | it('should not pull in transitive dependency mutating Object prototype', function () { 50 | if (!isBrowser) { 51 | expect({}.should).to.be.undefined; 52 | } 53 | }); 54 | }); 55 | 56 | 57 | // The "Converter" test suite above validates that all conversions are as expected. 58 | // It focuses on validating that the JavaScript object has the right content. 59 | // It does not check how the object is Marshaled out. 60 | // 61 | // The "Converter & Output Syntax" suite run a few similar tests 62 | // but focuses on validating that the output is json or yaml. 63 | // basically, it tests the various values that can be passed to spec.stringify 64 | describe('Converter & Output Syntax', function() { 65 | this.timeout(10000); 66 | SyntaxTestCases.forEach(function(testCase) { 67 | var testName = 'should convert ' + testCase.in.file + 68 | ' from ' + testCase.in.format + ' to ' + testCase.out.format + 69 | ' and output as ' + testCase.out.syntax + 70 | ' with ' + testCase.out.order + ' order'; 71 | 72 | it(testName, function(done) { 73 | convertFile(testCase) 74 | .then(function(spec) { 75 | var options = {syntax: testCase.out.syntax, order: testCase.out.order} 76 | var specAsString = spec.stringify(options) + '\n' 77 | var outfile = getFileName('output', testCase.out); 78 | 79 | if (WRITE_GOLDEN) 80 | FS.writeFileSync(outfile, specAsString); 81 | 82 | getFileRaw(outfile, function(err, goldenString) { 83 | try { 84 | expect(specAsString).to.deep.equal(goldenString); 85 | } catch(e) { 86 | return done(e); 87 | } 88 | done(); 89 | }); 90 | }) 91 | .catch(function (e) { 92 | done(e); 93 | }); 94 | }) 95 | }) 96 | }); 97 | -------------------------------------------------------------------------------- /test/input/api_blueprint/parameters.md: -------------------------------------------------------------------------------- 1 | FORMAT: 1A 2 | 3 | # Parameters API 4 | In this installment of the API Blueprint course we will discuss how to describe URI parameters. 5 | 6 | But first let's add more messages to our system. For that we would need introduce an message identifier – id. This id will be our parameter when communicating with our API about messages. 7 | 8 | ## API Blueprint 9 | + [Previous: Requests](06.%20Requests.md) 10 | + [This: Raw API Blueprint](https://raw.github.com/apiaryio/api-blueprint/master/examples/07.%20Parameters.md) 11 | + [Next: Attributes](08.%20Attributes.md) 12 | 13 | # Group Messages 14 | Group of all messages-related resources. 15 | 16 | ## My Message [/message/{id}] 17 | Here we have added the message `id` parameter as an [URI Template variable](http://tools.ietf.org/html/rfc6570) in the Message resource's URI. 18 | Note the parameter name `id` is enclosed in curly brackets. We will discuss this parameter in the `Parameters` section below, where we will also set its example value to `1` and declare it of an arbitrary 'number' type. 19 | 20 | + Parameters 21 | 22 | + id: 1 (number) - An unique identifier of the message. 23 | 24 | ### Retrieve a Message [GET] 25 | 26 | + Request Plain Text Message 27 | 28 | + Headers 29 | 30 | Accept: text/plain 31 | 32 | + Response 200 (text/plain) 33 | 34 | + Headers 35 | 36 | X-My-Message-Header: 42 37 | 38 | + Body 39 | 40 | Hello World! 41 | 42 | + Request JSON Message 43 | 44 | + Headers 45 | 46 | Accept: application/json 47 | 48 | + Response 200 (application/json) 49 | 50 | + Headers 51 | 52 | X-My-Message-Header: 42 53 | 54 | + Body 55 | 56 | { 57 | "id": 1, 58 | "message": "Hello World!" 59 | } 60 | 61 | ### Update a Message [PUT] 62 | 63 | + Request Update Plain Text Message (text/plain) 64 | 65 | All your base are belong to us. 66 | 67 | + Request Update JSON Message (application/json) 68 | 69 | { "message": "All your base are belong to us." } 70 | 71 | + Response 204 72 | 73 | ## All My Messages [/messages{?limit,page}] 74 | A resource representing all of my messages in the system. 75 | 76 | We have added the query URI template parameter - `limit`. This parameter is used for limiting the number of results returned by some actions on this resource. It does not affect every possible action of this resource therefore we will discuss it only at the particular action level below. 77 | 78 | ### Retrieve all Messages [GET] 79 | 80 | + Parameters 81 | 82 | + limit (number, optional) - The maximum number of results to return. 83 | + Default: `20` 84 | + page (integer, optional) - Which page of results to return 85 | 86 | + Response 200 (application/json) 87 | 88 | [ 89 | { 90 | "id": 1, 91 | "message": "Hello World!" 92 | }, 93 | { 94 | "id": 2, 95 | "message": "Time is an illusion. Lunchtime doubly so." 96 | }, 97 | { 98 | "id": 3, 99 | "message": "So long, and thanks for all the fish." 100 | } 101 | ] 102 | -------------------------------------------------------------------------------- /test/input/api_blueprint/polls_api.md: -------------------------------------------------------------------------------- 1 | FORMAT: 1A 2 | HOST: http://polls.apiblueprint.org/ 3 | 4 | # Polls 5 | 6 | Polls is a simple API allowing consumers to view polls and vote in them. You can view this documentation over at [Apiary](http://docs.pollsapi.apiary.io). 7 | 8 | # Polls API Root [/] 9 | 10 | This resource does not have any attributes. Instead it offers the initial API affordances in the form of the links in the JSON body. 11 | 12 | It is recommend to follow the “url” link values, [Link](https://tools.ietf.org/html/rfc5988) or Location headers where applicable to retrieve resources. Instead of constructing your own URLs, to keep your client decoupled from implementation details. 13 | 14 | ## Retrieve the Entry Point [GET] 15 | 16 | + Response 200 (application/json) 17 | 18 | { 19 | "questions_url": "/questions" 20 | } 21 | 22 | ## Group Question 23 | 24 | Resources related to questions in the API. 25 | 26 | ## Question [/questions/{question_id}] 27 | 28 | A Question object has the following attributes: 29 | 30 | + question 31 | + published_at - An ISO8601 date when the question was published. 32 | + url 33 | + choices - An array of Choice objects. 34 | 35 | + Parameters 36 | + question_id: 1 (required, number) - ID of the Question in form of an integer 37 | 38 | ### View a Questions Detail [GET] 39 | 40 | + Response 200 (application/json) 41 | 42 | { 43 | "question": "Favourite programming language?", 44 | "published_at": "2014-11-11T08:40:51.620Z", 45 | "url": "/questions/1", 46 | "choices": [ 47 | { 48 | "choice": "Swift", 49 | "url": "/questions/1/choices/1", 50 | "votes": 2048 51 | }, { 52 | "choice": "Python", 53 | "url": "/questions/1/choices/2", 54 | "votes": 1024 55 | }, { 56 | "choice": "Objective-C", 57 | "url": "/questions/1/choices/3", 58 | "votes": 512 59 | }, { 60 | "choice": "Ruby", 61 | "url": "/questions/1/choices/4", 62 | "votes": 256 63 | } 64 | ] 65 | } 66 | 67 | ## Choice [/questions/{question_id}/choices/{choice_id}] 68 | 69 | + Parameters 70 | + question_id: 1 (required, number) - ID of the Question in form of an integer 71 | + choice_id: 1 (required, number) - ID of the Choice in form of an integer 72 | 73 | ### Vote on a Choice [POST] 74 | 75 | This action allows you to vote on a question's choice. 76 | 77 | + Response 201 78 | 79 | + Headers 80 | 81 | Location: /questions/1 82 | 83 | ## Questions Collection [/questions{?page}] 84 | 85 | + Parameters 86 | + page: 1 (optional, number) - The page of questions to return 87 | 88 | ### List All Questions [GET] 89 | 90 | + Response 200 (application/json) 91 | 92 | + Headers 93 | 94 | Link: ; rel="next" 95 | 96 | + Body 97 | 98 | [ 99 | { 100 | "question": "Favourite programming language?", 101 | "published_at": "2014-11-11T08:40:51.620Z", 102 | "url": "/questions/1", 103 | "choices": [ 104 | { 105 | "choice": "Swift", 106 | "url": "/questions/1/choices/1", 107 | "votes": 2048 108 | }, { 109 | "choice": "Python", 110 | "url": "/questions/1/choices/2", 111 | "votes": 1024 112 | }, { 113 | "choice": "Objective-C", 114 | "url": "/questions/1/choices/3", 115 | "votes": 512 116 | }, { 117 | "choice": "Ruby", 118 | "url": "/questions/1/choices/4", 119 | "votes": 256 120 | } 121 | ] 122 | } 123 | ] 124 | 125 | ### Create a New Question [POST] 126 | 127 | You may create your own question using this action. It takes a JSON object containing a question and a collection of answers in the form of choices. 128 | 129 | + question (string) - The question 130 | + choices (array[string]) - A collection of choices. 131 | 132 | + Request (application/json) 133 | 134 | { 135 | "question": "Favourite programming language?", 136 | "choices": [ 137 | "Swift", 138 | "Python", 139 | "Objective-C", 140 | "Ruby" 141 | ] 142 | } 143 | 144 | + Response 201 (application/json) 145 | 146 | + Headers 147 | 148 | Location: /questions/2 149 | 150 | + Body 151 | 152 | { 153 | "question": "Favourite programming language?", 154 | "published_at": "2014-11-11T08:40:51.620Z", 155 | "url": "/questions/2", 156 | "choices": [ 157 | { 158 | "choice": "Swift", 159 | "url": "/questions/2/choices/1", 160 | "votes": 0 161 | }, { 162 | "choice": "Python", 163 | "url": "/questions/2/choices/2", 164 | "votes": 0 165 | }, { 166 | "choice": "Objective-C", 167 | "url": "/questions/2/choices/3", 168 | "votes": 0 169 | }, { 170 | "choice": "Ruby", 171 | "url": "/questions/2/choices/4", 172 | "votes": 0 173 | } 174 | ] 175 | } 176 | 177 | -------------------------------------------------------------------------------- /test/input/api_blueprint/simplest.md: -------------------------------------------------------------------------------- 1 | FORMAT: 1A 2 | 3 | # The Simplest API 4 | This is one of the simplest APIs written in the **API Blueprint**. 5 | One plain resource combined with a method and that's it! We will explain what is going on in the next installment - [Resource and Actions](02.%20Resource%20and%20Actions.md). 6 | 7 | **Note:** As we progress through the examples, do not also forget to view the [Raw](https://raw.github.com/apiaryio/api-blueprint/master/examples/01.%20Simplest%20API.md) code to see what is really going on in the API Blueprint, as opposed to just seeing the output of the Github Markdown parser. 8 | 9 | Also please keep in mind that every single example in this course is a **real API Blueprint** and as such you can **parse** it with the [API Blueprint parser](https://github.com/apiaryio/drafter) or one of its [bindings](https://github.com/apiaryio/drafter#bindings). 10 | 11 | ## API Blueprint 12 | + [This: Raw API Blueprint](https://raw.github.com/apiaryio/api-blueprint/master/examples/01.%20Simplest%20API.md) 13 | + [Next: Resource and Actions](02.%20Resource%20and%20Actions.md) 14 | 15 | # GET /message 16 | + Response 200 (text/plain) 17 | 18 | Hello World! 19 | -------------------------------------------------------------------------------- /test/input/openapi_3/common_params.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "version": "0.0.1", 5 | "title": "testcommonparams" 6 | }, 7 | "paths": { 8 | "/resource/{id}": { 9 | "parameters": [ 10 | { 11 | "name": "id", 12 | "in": "path", 13 | "example": 0, 14 | "schema": { 15 | "type": "integer" 16 | } 17 | }, 18 | { 19 | "name": "name" 20 | } 21 | ] 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/input/openapi_3/deprecated.yml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | version: 0.0.1 4 | title: >- 5 | API with deprecated schemas and operations 6 | 7 | See https://github.com/Azure/autorest/tree/master/Samples/test/deprecated 8 | for description of x-deprecated as supported by Autorest 9 | paths: 10 | /path1: 11 | get: 12 | deprecated: true 13 | responses: 14 | '200': 15 | description: Deprecated operation 1 16 | content: 17 | application/json: 18 | schema: 19 | $ref: '#/components/schemas/Schema1' 20 | operationId: getPath1 21 | /path2: 22 | get: 23 | deprecated: true 24 | x-deprecated: 25 | description: Deprecation info 26 | responses: 27 | '200': 28 | description: Deprecated operation 2 29 | content: 30 | application/json: 31 | schema: 32 | $ref: '#/components/schemas/Schema2' 33 | operationId: getPath2 34 | /path3: 35 | get: 36 | responses: 37 | '200': 38 | description: Operation 3 39 | content: 40 | application/json: 41 | schema: 42 | $ref: '#/components/schemas/Schema3' 43 | operationId: getPath3 44 | components: 45 | schemas: 46 | Schema1: 47 | deprecated: true 48 | type: object 49 | properties: 50 | prop1: 51 | x-deprecated: 52 | description: Prop deprecation info 53 | type: string 54 | prop2: 55 | deprecated: true 56 | x-deprecated: 57 | description: Prop also deprecated 58 | type: string 59 | prop3: 60 | deprecated: false 61 | type: integer 62 | Schema2: 63 | deprecated: true 64 | x-deprecated: 65 | replaced-by: Schema1 66 | type: object 67 | properties: 68 | prop4: 69 | deprecated: true 70 | type: string 71 | prop5: 72 | type: array 73 | items: 74 | deprecated: true 75 | type: string 76 | Schema3: 77 | deprecated: false 78 | type: array 79 | items: 80 | type: string 81 | -------------------------------------------------------------------------------- /test/input/openapi_3/external_ref.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "string" 3 | } 4 | -------------------------------------------------------------------------------- /test/input/openapi_3/external_ref_fragment.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "responses": { 4 | "Error": { 5 | "description": "Error response" 6 | } 7 | } 8 | } 9 | 10 | -------------------------------------------------------------------------------- /test/input/openapi_3/form_param.yml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | version: 0.0.1 4 | title: test 5 | paths: 6 | /foo: 7 | post: 8 | requestBody: 9 | required: true 10 | content: 11 | multipart/form-data: 12 | schema: 13 | type: object 14 | properties: 15 | name: 16 | type: string 17 | format: 18 | $ref: '#/components/schemas/ImageFormat' 19 | uploadDate: 20 | type: string 21 | format: date-time 22 | readOnly: true 23 | image: 24 | type: string 25 | format: binary 26 | required: 27 | - image 28 | responses: 29 | '200': 30 | description: Foo 31 | content: 32 | application/json: 33 | schema: 34 | type: object 35 | tags: 36 | - Foos 37 | operationId: getFoo 38 | components: 39 | schemas: 40 | ImageFormat: 41 | type: string 42 | enum: 43 | - gif 44 | - jpeg 45 | - png 46 | x-ms-enum: 47 | name: ImageType 48 | modelAsString: true 49 | -------------------------------------------------------------------------------- /test/input/openapi_3/has_external_ref.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "title": "Nodejs", 4 | "version": "1.0.0" 5 | }, 6 | "openapi": "3.0.0", 7 | "paths": { 8 | "/articles": { 9 | "get": { 10 | "operationId": "ArticleController.getAll", 11 | "responses": { 12 | "200": { 13 | "content": { 14 | "application/json": { 15 | "schema": { 16 | "$ref": "./external_ref.json" 17 | } 18 | } 19 | }, 20 | "description": "Successful response" 21 | }, 22 | "default": { 23 | "$ref": "./external_ref_fragment.json#/responses/Error" 24 | } 25 | }, 26 | "summary": "Get all", 27 | "tags": [ 28 | "Article" 29 | ] 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/input/openapi_3/minimal.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "title": "Nodejs", 4 | "version": "1.0.0" 5 | }, 6 | "openapi": "3.0.0", 7 | "paths": { 8 | "/articles": { 9 | "get": { 10 | "operationId": "ArticleController.getAll", 11 | "responses": { 12 | "200": { 13 | "content": { 14 | "application/json": {} 15 | }, 16 | "description": "Successful response" 17 | } 18 | }, 19 | "summary": "Get all", 20 | "tags": [ 21 | "Article" 22 | ] 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/input/openapi_3/multiple_ref.yml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | title: test 4 | description: |- 5 | test 6 | version: "2" 7 | paths: 8 | /testBodyRefIsResolved: 9 | post: 10 | summary: test 11 | description: |- 12 | test 13 | responses: 14 | '200': 15 | description: |- 16 | ok 17 | requestBody: 18 | $ref: '#/components/requestBodies/Value' 19 | /testSameBodyRefIsResolvedAgain: 20 | post: 21 | summary: test 22 | description: |- 23 | test 24 | responses: 25 | '200': 26 | description: |- 27 | ok 28 | requestBody: 29 | $ref: '#/components/requestBodies/Value' 30 | servers: 31 | - url: https://somewhere.test 32 | description: above the clouds 33 | components: 34 | requestBodies: 35 | Value: 36 | content: 37 | application/json: 38 | schema: 39 | type: object 40 | example: {} 41 | description: |- 42 | Some content 43 | required: true -------------------------------------------------------------------------------- /test/input/openapi_3/nested_oneof.yml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | version: 0.0.1 4 | title: test 5 | paths: 6 | /foo: 7 | get: 8 | responses: 9 | '200': 10 | description: Foo 11 | content: 12 | application/hal+json: 13 | schema: 14 | $ref: '#/components/schemas/Foo' 15 | tags: 16 | - Foos 17 | operationId: getFoo 18 | components: 19 | schemas: 20 | SomeBar: 21 | type: string 22 | OtherBar: 23 | type: object 24 | properties: 25 | other: 26 | type: string 27 | Foo: 28 | type: object 29 | properties: 30 | bar: 31 | oneOf: 32 | - $ref: '#/components/schemas/SomeBar' 33 | - $ref: '#/components/schemas/OtherBar' 34 | -------------------------------------------------------------------------------- /test/input/openapi_3/nullable.yml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | version: 0.0.1 4 | title: test 5 | paths: 6 | /foo: 7 | get: 8 | responses: 9 | '200': 10 | description: Foo 11 | content: 12 | application/hal+json: 13 | schema: 14 | $ref: '#/components/schemas/Foo' 15 | tags: 16 | - Foos 17 | operationId: getFoo 18 | components: 19 | schemas: 20 | Foo: 21 | type: string 22 | nullable: true 23 | -------------------------------------------------------------------------------- /test/input/openapi_3/param_schema_ref.yml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | version: 0.0.1 4 | title: testsickle 5 | paths: 6 | /user/account/{accountLevel}: 7 | post: 8 | parameters: 9 | - in: path 10 | name: accountLevel 11 | required: true 12 | schema: 13 | $ref: "#/components/schemas/accountLevel" 14 | responses: 15 | 200: 16 | $ref: "#/components/responses/defaultResponse" 17 | # complex objects have schema definitions 18 | components: 19 | responses: 20 | defaultResponse: 21 | description: Success 22 | content: 23 | application/json: 24 | schema: 25 | $ref: '#/components/schemas/DefaultResponseObject' 26 | schemas: 27 | accountLevel: 28 | type: string 29 | enum: 30 | - one 31 | - two 32 | - three 33 | - four 34 | DefaultResponseObject: 35 | required: 36 | - message 37 | properties: 38 | message: 39 | type: string 40 | -------------------------------------------------------------------------------- /test/input/openapi_3/produces.yml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | version: 0.0.1 4 | title: test 5 | paths: 6 | /foo: 7 | get: 8 | responses: 9 | '200': 10 | description: Foo 11 | content: 12 | application/hal+json: 13 | schema: 14 | $ref: '#/components/schemas/Foo' 15 | default: 16 | description: Unexpected problem 17 | content: 18 | application/problem+json: 19 | schema: 20 | $ref: '#/components/schemas/Problem' 21 | tags: 22 | - Foos 23 | operationId: getFoo 24 | components: 25 | schemas: 26 | Foo: 27 | type: string 28 | Problem: 29 | type: string 30 | -------------------------------------------------------------------------------- /test/input/openapi_3/request_response_ref.yml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | version: 0.0.1 4 | title: test 5 | paths: 6 | /foo: 7 | post: 8 | requestBody: 9 | $ref: '#/components/requestBodies/FooRequest' 10 | responses: 11 | '200': 12 | $ref: '#/components/responses/FooResponse' 13 | tags: 14 | - Foos 15 | operationId: getFoo 16 | components: 17 | schemas: 18 | PetName: 19 | type: object 20 | properties: 21 | name: 22 | type: string 23 | nickname: 24 | type: string 25 | nullable: true 26 | requestBodies: 27 | FooRequest: 28 | required: true 29 | content: 30 | application/json: 31 | schema: 32 | type: object 33 | properties: 34 | name: 35 | type: string 36 | nullable: true 37 | pet: 38 | allOf: 39 | - $ref: '#/components/schemas/PetName' 40 | - type: object 41 | properties: 42 | favorite_foods: 43 | type: array 44 | items: 45 | type: string 46 | nullable: true 47 | responses: 48 | FooResponse: 49 | description: Foo 50 | content: 51 | application/json: 52 | schema: 53 | allOf: 54 | - $ref: '#/components/schemas/PetName' 55 | - type: object 56 | properties: 57 | name: 58 | type: string 59 | nullable: true 60 | -------------------------------------------------------------------------------- /test/input/openapi_3/servers.yml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.1 2 | info: 3 | title: Sample API 4 | description: API description in Markdown. 5 | version: 1.0.0 6 | servers: 7 | - url: '{scheme}://{host}{basePath}' 8 | variables: 9 | scheme: 10 | default: https 11 | host: 12 | default: api.example.com 13 | basePath: 14 | default: /api 15 | -------------------------------------------------------------------------------- /test/input/openapi_3/slash_ref.yml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.1 2 | info: 3 | title: Sample API 4 | description: API description in Markdown. 5 | version: 1.0.0 6 | servers: 7 | - url: 'https://api.example.com' 8 | paths: 9 | /users~: 10 | get: 11 | summary: Returns a list of users. 12 | description: Optional extended description in Markdown. 13 | responses: 14 | '200': 15 | description: OK 16 | /other_users: 17 | $ref: '#/paths/~1users~0' 18 | -------------------------------------------------------------------------------- /test/input/openapi_3/yaml_ref.yml: -------------------------------------------------------------------------------- 1 | type: string 2 | -------------------------------------------------------------------------------- /test/input/openapi_3/yaml_with_ref.yml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | version: 0.0.1 4 | title: testsickle 5 | paths: 6 | '/api/v2/user/{id}': 7 | get: 8 | tags: 9 | - User 10 | summary: Get user 11 | operationId: user.get 12 | parameters: 13 | - name: id 14 | in: path 15 | schema: 16 | $ref: 'yaml_ref.yml' 17 | -------------------------------------------------------------------------------- /test/input/raml/XKCD/api.raml: -------------------------------------------------------------------------------- 1 | #%RAML 0.8 2 | title: XKCD 3 | baseUri: http://xkcd.com 4 | schemas: 5 | - comic: !include schemas/comic-schema.json 6 | /{comicId}/info.0.json: 7 | get: 8 | description: | 9 | Fetch comics and metadata by comic id. 10 | responses: 11 | 200: 12 | body: 13 | application/json: 14 | schema: comic 15 | example: !include examples/comic-example.json 16 | /info.0.json: 17 | get: 18 | description: | 19 | Fetch current comic and metadata. 20 | responses: 21 | 200: 22 | body: 23 | application/json: 24 | schema: comic 25 | example: !include examples/comic-example.json 26 | documentation: 27 | - title: Headline 28 | content: !include docs/headline.md -------------------------------------------------------------------------------- /test/input/raml/XKCD/docs/headline.md: -------------------------------------------------------------------------------- 1 | A webcomic of romance, sarcasm, math, and language. -------------------------------------------------------------------------------- /test/input/raml/XKCD/examples/comic-example.json: -------------------------------------------------------------------------------- 1 | { 2 | "month" : "4" , 3 | "num" : 1362 , 4 | "link" : "" , 5 | "year" : "2014" , 6 | "news" : "" , 7 | "safe_title" : "Morse Code" , 8 | "transcript" : "" , 9 | "alt" : "Oh, because Facebook has worked out SO WELL for everyone." , 10 | "img" : "http://imgs.xkcd.com/comics/morse_code.png" , 11 | "title" : "Morse Code" , 12 | "day" : "30" 13 | } -------------------------------------------------------------------------------- /test/input/raml/XKCD/schemas/comic-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "required" : true , 3 | "$schema" : "http://json-schema.org/draft-03/schema" , 4 | "type" : "object" , 5 | "properties" : { 6 | "month" : { 7 | "type" : "string" , 8 | "required" : false 9 | } , 10 | "num" : { 11 | "type" : "number" , 12 | "required" : false 13 | } , 14 | "link" : { 15 | "type" : "string" , 16 | "required" : false 17 | } , 18 | "year" : { 19 | "type" : "string" , 20 | "required" : false 21 | } , 22 | "news" : { 23 | "type" : "string" , 24 | "required" : false 25 | } , 26 | "safe_title" : { 27 | "type" : "string" , 28 | "required" : false 29 | } , 30 | "transcript" : { 31 | "type" : "string" , 32 | "required" : false 33 | } , 34 | "alt" : { 35 | "type" : "string" , 36 | "required" : false 37 | } , 38 | "img" : { 39 | "type" : "string" , 40 | "required" : false 41 | } , 42 | "title" : { 43 | "type" : "string" , 44 | "required" : false 45 | } , 46 | "day" : { 47 | "type" : "string" , 48 | "required" : false 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /test/input/swagger_1/petstore/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiVersion": "1.0.0", 3 | "swaggerVersion": "1.2", 4 | "apis": [ 5 | { 6 | "path": "/../pet.{format}", 7 | "description": "Operations about pets" 8 | }, 9 | { 10 | "path": "/../user.{format}", 11 | "description": "Operations about user" 12 | }, 13 | { 14 | "path": "/../store.{format}", 15 | "description": "Operations about store" 16 | } 17 | ], 18 | "authorizations": { 19 | "oauth2": { 20 | "type": "oauth2", 21 | "scopes": [ 22 | { 23 | "scope": "write:pets", 24 | "description": "Modify pets in your account" 25 | }, 26 | { 27 | "scope": "read:pets", 28 | "description": "Read your pets" 29 | } 30 | ], 31 | "grantTypes": { 32 | "implicit": { 33 | "loginEndpoint": { 34 | "url": "http://petstore.swagger.wordnik.com/api/oauth/dialog" 35 | }, 36 | "tokenName": "access_token" 37 | }, 38 | "authorization_code": { 39 | "tokenRequestEndpoint": { 40 | "url": "http://petstore.swagger.wordnik.com/api/oauth/requestToken", 41 | "clientIdName": "client_id", 42 | "clientSecretName": "client_secret" 43 | }, 44 | "tokenEndpoint": { 45 | "url": "http://petstore.swagger.wordnik.com/api/oauth/token", 46 | "tokenName": "auth_code" 47 | } 48 | } 49 | } 50 | } 51 | }, 52 | "info": { 53 | "title": "Swagger Sample App", 54 | "description": "This is a sample server Petstore server. You can find out more about Swagger \n at http://swagger.wordnik.com or on irc.freenode.net, #swagger. For this sample,\n you can use the api key \"special-key\" to test the authorization filters", 55 | "termsOfServiceUrl": "http://helloreverb.com/terms/", 56 | "contact": "apiteam@wordnik.com", 57 | "license": "Apache 2.0", 58 | "licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.html" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /test/input/swagger_1/petstore/store.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiVersion": "1.0.0", 3 | "swaggerVersion": "1.2", 4 | "basePath": "http://petstore.swagger.wordnik.com/api", 5 | "resourcePath": "/store", 6 | "produces": [ 7 | "application/json" 8 | ], 9 | "apis": [ 10 | { 11 | "path": "/store/order", 12 | "operations": [ 13 | { 14 | "method": "POST", 15 | "summary": "Place an order for a pet", 16 | "notes": "", 17 | "type": "void", 18 | "nickname": "placeOrder", 19 | "authorizations": { 20 | "oauth2": [ 21 | { 22 | "scope": "write:pets", 23 | "description": "write to your pets" 24 | } 25 | ] 26 | }, 27 | "parameters": [ 28 | { 29 | "name": "body", 30 | "description": "order placed for purchasing the pet", 31 | "required": true, 32 | "type": "Order", 33 | "paramType": "body", 34 | "allowMultiple": false 35 | } 36 | ], 37 | "responseMessages": [ 38 | { 39 | "code": 400, 40 | "message": "Invalid order" 41 | } 42 | ] 43 | } 44 | ] 45 | }, 46 | { 47 | "path": "/store/order/{orderId}", 48 | "operations": [ 49 | { 50 | "method": "DELETE", 51 | "summary": "Delete purchase order by ID", 52 | "notes": "For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors", 53 | "type": "void", 54 | "nickname": "deleteOrder", 55 | "authorizations": { 56 | "oauth2": [ 57 | { 58 | "scope": "write:pets", 59 | "description": "write to your pets" 60 | } 61 | ] 62 | }, 63 | "parameters": [ 64 | { 65 | "name": "orderId", 66 | "description": "ID of the order that needs to be deleted", 67 | "required": true, 68 | "type": "string", 69 | "paramType": "path", 70 | "allowMultiple": false 71 | } 72 | ], 73 | "responseMessages": [ 74 | { 75 | "code": 400, 76 | "message": "Invalid ID supplied" 77 | }, 78 | { 79 | "code": 404, 80 | "message": "Order not found" 81 | } 82 | ] 83 | }, 84 | { 85 | "method": "GET", 86 | "summary": "Find purchase order by ID", 87 | "notes": "For valid response try integer IDs with value <= 5. Anything above 5 or nonintegers will generate API errors", 88 | "type": "Order", 89 | "nickname": "getOrderById", 90 | "authorizations": {}, 91 | "parameters": [ 92 | { 93 | "name": "orderId", 94 | "description": "ID of pet that needs to be fetched", 95 | "required": true, 96 | "type": "string", 97 | "paramType": "path", 98 | "allowMultiple": false 99 | } 100 | ], 101 | "responseMessages": [ 102 | { 103 | "code": 400, 104 | "message": "Invalid ID supplied" 105 | }, 106 | { 107 | "code": 404, 108 | "message": "Order not found" 109 | } 110 | ] 111 | } 112 | ] 113 | } 114 | ], 115 | "models": { 116 | "Order": { 117 | "id": "Order", 118 | "properties": { 119 | "id": { 120 | "type": "integer", 121 | "format": "int64" 122 | }, 123 | "petId": { 124 | "type": "integer", 125 | "format": "int64" 126 | }, 127 | "quantity": { 128 | "type": "integer", 129 | "format": "int32" 130 | }, 131 | "status": { 132 | "type": "string", 133 | "description": "Order Status", 134 | "enum": [ 135 | "placed", 136 | " approved", 137 | " delivered" 138 | ] 139 | }, 140 | "shipDate": { 141 | "type": "string", 142 | "format": "date-time" 143 | } 144 | } 145 | } 146 | } 147 | } -------------------------------------------------------------------------------- /test/input/wadl/regex_paths.wadl: -------------------------------------------------------------------------------- 1 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /test/output/openapi_3/OpenStack_example.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "title": "", 4 | "version": "" 5 | }, 6 | "openapi": "3.0.0", 7 | "paths": { 8 | "/": { 9 | "get": { 10 | "operationId": "listVersions-v2", 11 | "responses": { 12 | "200": { 13 | "description": "Successful Response" 14 | } 15 | } 16 | }, 17 | "parameters": [] 18 | }, 19 | "/v2.0": { 20 | "get": { 21 | "operationId": "showVersionInfo-v2.0", 22 | "responses": { 23 | "200": { 24 | "description": "Successful Response" 25 | } 26 | } 27 | }, 28 | "parameters": [] 29 | }, 30 | "/v2.0/extensions": { 31 | "get": { 32 | "operationId": "listExtensions-v2", 33 | "responses": { 34 | "200": { 35 | "description": "Successful Response" 36 | } 37 | } 38 | }, 39 | "parameters": [] 40 | }, 41 | "/v2.0/extensions/{alias}": { 42 | "get": { 43 | "operationId": "showExtension-v2", 44 | "responses": { 45 | "200": { 46 | "description": "Successful Response" 47 | } 48 | } 49 | }, 50 | "parameters": [ 51 | { 52 | "in": "path", 53 | "name": "alias", 54 | "required": true, 55 | "schema": { 56 | "type": "string" 57 | } 58 | } 59 | ] 60 | }, 61 | "/v2.0/tenants": { 62 | "get": { 63 | "operationId": "listTenants", 64 | "responses": { 65 | "200": { 66 | "description": "Successful Response" 67 | } 68 | } 69 | }, 70 | "parameters": [ 71 | { 72 | "in": "header", 73 | "name": "X-Auth-Token", 74 | "required": true, 75 | "schema": { 76 | "type": "string" 77 | } 78 | }, 79 | { 80 | "in": "query", 81 | "name": "limit", 82 | "required": false, 83 | "schema": { 84 | "format": "int32", 85 | "type": "integer" 86 | } 87 | }, 88 | { 89 | "in": "query", 90 | "name": "marker", 91 | "required": false, 92 | "schema": { 93 | "type": "string" 94 | } 95 | } 96 | ] 97 | }, 98 | "/v2.0/tokens": { 99 | "parameters": [], 100 | "post": { 101 | "operationId": "authenticate-v2.0", 102 | "responses": { 103 | "200": { 104 | "description": "Successful Response" 105 | } 106 | } 107 | } 108 | } 109 | }, 110 | "servers": [ 111 | { 112 | "url": "http://localhost:35357/" 113 | } 114 | ] 115 | } 116 | -------------------------------------------------------------------------------- /test/output/openapi_3/XKCD.json: -------------------------------------------------------------------------------- 1 | { 2 | "components": { 3 | "schemas": { 4 | "comic": { 5 | "properties": { 6 | "alt": { 7 | "type": "string" 8 | }, 9 | "day": { 10 | "type": "string" 11 | }, 12 | "img": { 13 | "type": "string" 14 | }, 15 | "link": { 16 | "type": "string" 17 | }, 18 | "month": { 19 | "type": "string" 20 | }, 21 | "news": { 22 | "type": "string" 23 | }, 24 | "num": { 25 | "type": "number" 26 | }, 27 | "safe_title": { 28 | "type": "string" 29 | }, 30 | "title": { 31 | "type": "string" 32 | }, 33 | "transcript": { 34 | "type": "string" 35 | }, 36 | "year": { 37 | "type": "string" 38 | } 39 | }, 40 | "type": "object" 41 | } 42 | } 43 | }, 44 | "info": { 45 | "title": "XKCD", 46 | "version": "" 47 | }, 48 | "openapi": "3.0.0", 49 | "paths": { 50 | "/info.0.json": { 51 | "get": { 52 | "description": "Fetch current comic and metadata.\n", 53 | "responses": { 54 | "200": { 55 | "content": { 56 | "*/*": { 57 | "schema": { 58 | "$ref": "#/components/schemas/comic" 59 | } 60 | } 61 | }, 62 | "description": "OK" 63 | } 64 | } 65 | } 66 | }, 67 | "/{comicId}/info.0.json": { 68 | "get": { 69 | "description": "Fetch comics and metadata by comic id.\n", 70 | "parameters": [ 71 | { 72 | "in": "path", 73 | "name": "comicId", 74 | "required": true, 75 | "schema": { 76 | "type": "string" 77 | } 78 | } 79 | ], 80 | "responses": { 81 | "200": { 82 | "content": { 83 | "*/*": { 84 | "schema": { 85 | "$ref": "#/components/schemas/comic" 86 | } 87 | } 88 | }, 89 | "description": "OK" 90 | } 91 | } 92 | } 93 | } 94 | }, 95 | "servers": [ 96 | { 97 | "url": "http://xkcd.com/" 98 | } 99 | ] 100 | } 101 | -------------------------------------------------------------------------------- /test/output/openapi_3/klout.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "title": "Partner API v2", 4 | "version": "" 5 | }, 6 | "openapi": "3.0.0", 7 | "paths": { 8 | "/identity.json/gp/{google_plus_id}": { 9 | "get": { 10 | "parameters": [ 11 | { 12 | "description": "A Google+ ID (e.g. 112620727907435773834)", 13 | "in": "path", 14 | "name": "google_plus_id", 15 | "required": true, 16 | "schema": { 17 | "default": "112620727907435773834", 18 | "type": "string" 19 | } 20 | } 21 | ], 22 | "responses": { 23 | "200": { 24 | "description": "success" 25 | } 26 | } 27 | } 28 | }, 29 | "/identity.json/ig/{instagram_id}": { 30 | "get": { 31 | "parameters": [ 32 | { 33 | "description": "An Instagram ID (e.g. 816029)", 34 | "in": "path", 35 | "name": "instagram_id", 36 | "required": true, 37 | "schema": { 38 | "default": "816029", 39 | "type": "string" 40 | } 41 | } 42 | ], 43 | "responses": { 44 | "200": { 45 | "description": "success" 46 | } 47 | } 48 | } 49 | }, 50 | "/identity.json/klout/{klout_id}/tw": { 51 | "get": { 52 | "parameters": [ 53 | { 54 | "description": "A KloutId (like 635263)", 55 | "in": "path", 56 | "name": "klout_id", 57 | "required": true, 58 | "schema": { 59 | "default": "635263", 60 | "type": "string" 61 | } 62 | } 63 | ], 64 | "responses": { 65 | "200": { 66 | "description": "success" 67 | } 68 | } 69 | } 70 | }, 71 | "/identity.json/tw/{twitter_id}": { 72 | "get": { 73 | "parameters": [ 74 | { 75 | "description": "A twitter ID (e.g. 500042487)", 76 | "in": "query", 77 | "name": "twitter_id", 78 | "schema": { 79 | "default": "500042487", 80 | "type": "string" 81 | } 82 | } 83 | ], 84 | "responses": { 85 | "200": { 86 | "description": "success" 87 | } 88 | } 89 | } 90 | }, 91 | "/identity.json/twitter": { 92 | "get": { 93 | "parameters": [ 94 | { 95 | "description": "A twitter screen name (e.g. jtimberlake)", 96 | "in": "query", 97 | "name": "screenName", 98 | "schema": { 99 | "default": "jtimberlake", 100 | "type": "string" 101 | } 102 | } 103 | ], 104 | "responses": { 105 | "200": { 106 | "description": "success" 107 | } 108 | } 109 | } 110 | }, 111 | "/user.json/{kloutId}": { 112 | "get": { 113 | "parameters": [ 114 | { 115 | "description": "A kloutId (like 635263)", 116 | "in": "path", 117 | "name": "kloutId", 118 | "required": true, 119 | "schema": { 120 | "default": "635263", 121 | "type": "string" 122 | } 123 | } 124 | ], 125 | "responses": { 126 | "200": { 127 | "description": "success" 128 | } 129 | } 130 | } 131 | }, 132 | "/user.json/{kloutId}/influence": { 133 | "get": { 134 | "parameters": [ 135 | { 136 | "description": "A kloutId (like 635263)", 137 | "in": "path", 138 | "name": "kloutId", 139 | "required": true, 140 | "schema": { 141 | "default": "635263", 142 | "type": "string" 143 | } 144 | } 145 | ], 146 | "responses": { 147 | "200": { 148 | "description": "success" 149 | } 150 | } 151 | } 152 | }, 153 | "/user.json/{kloutId}/score": { 154 | "get": { 155 | "parameters": [ 156 | { 157 | "description": "A kloutId (like 635263)", 158 | "in": "path", 159 | "name": "kloutId", 160 | "required": true, 161 | "schema": { 162 | "default": "635263", 163 | "type": "string" 164 | } 165 | } 166 | ], 167 | "responses": { 168 | "200": { 169 | "description": "success" 170 | } 171 | } 172 | } 173 | }, 174 | "/user.json/{kloutId}/topics": { 175 | "get": { 176 | "parameters": [ 177 | { 178 | "description": "A kloutId (like 635263)", 179 | "in": "path", 180 | "name": "kloutId", 181 | "required": true, 182 | "schema": { 183 | "default": "635263", 184 | "type": "string" 185 | } 186 | } 187 | ], 188 | "responses": { 189 | "200": { 190 | "description": "success" 191 | } 192 | } 193 | } 194 | } 195 | }, 196 | "servers": [ 197 | { 198 | "url": "http:://api.klout.com/v2" 199 | } 200 | ] 201 | } 202 | -------------------------------------------------------------------------------- /test/output/openapi_3/parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "components": { 3 | "schemas": { 4 | "All_My_Messages": {}, 5 | "My_Message": {} 6 | } 7 | }, 8 | "info": { 9 | "description": "In this installment of the API Blueprint course we will discuss how to describe URI parameters.\n\nBut first let's add more messages to our system. For that we would need introduce an message identifier – id. This id will be our parameter when communicating with our API about messages.\n\n## API Blueprint\n\n+ [Previous: Requests](06.%20Requests.md)\n\n+ [This: Raw API Blueprint](https://raw.github.com/apiaryio/api-blueprint/master/examples/07.%20Parameters.md)\n\n+ [Next: Attributes](08.%20Attributes.md)", 10 | "title": "Parameters API", 11 | "version": "" 12 | }, 13 | "openapi": "3.0.0", 14 | "paths": { 15 | "/message/{id}": { 16 | "get": { 17 | "description": "", 18 | "parameters": [ 19 | { 20 | "description": "An unique identifier of the message.", 21 | "example": "1", 22 | "in": "path", 23 | "name": "id", 24 | "required": true, 25 | "schema": { 26 | "type": "number" 27 | } 28 | }, 29 | { 30 | "description": "e.g. text/plain", 31 | "example": "text/plain", 32 | "in": "header", 33 | "name": "Accept", 34 | "required": false, 35 | "schema": { 36 | "type": "string" 37 | } 38 | } 39 | ], 40 | "responses": { 41 | "200": { 42 | "content": { 43 | "application/json": { 44 | "examples": { 45 | "response": { 46 | "value": { 47 | "id": 1, 48 | "message": "Hello World!" 49 | } 50 | } 51 | } 52 | } 53 | }, 54 | "description": "OK", 55 | "headers": {} 56 | } 57 | }, 58 | "summary": "Retrieve a Message", 59 | "tags": [ 60 | "Messages" 61 | ] 62 | }, 63 | "put": { 64 | "description": "", 65 | "parameters": [ 66 | { 67 | "description": "An unique identifier of the message.", 68 | "example": "1", 69 | "in": "path", 70 | "name": "id", 71 | "required": true, 72 | "schema": { 73 | "type": "number" 74 | } 75 | } 76 | ], 77 | "requestBody": { 78 | "content": { 79 | "application/json": { 80 | "schema": { 81 | "example": { 82 | "message": "All your base are belong to us." 83 | }, 84 | "properties": { 85 | "message": { 86 | "type": "string" 87 | } 88 | }, 89 | "type": "object" 90 | } 91 | } 92 | } 93 | }, 94 | "responses": { 95 | "204": { 96 | "description": "No Content", 97 | "headers": {} 98 | } 99 | }, 100 | "summary": "Update a Message", 101 | "tags": [ 102 | "Messages" 103 | ] 104 | } 105 | }, 106 | "/messages": { 107 | "get": { 108 | "description": "", 109 | "parameters": [ 110 | { 111 | "description": "The maximum number of results to return.", 112 | "in": "query", 113 | "name": "limit", 114 | "required": false, 115 | "schema": { 116 | "default": 20, 117 | "type": "number" 118 | } 119 | }, 120 | { 121 | "description": "Which page of results to return", 122 | "in": "query", 123 | "name": "page", 124 | "required": false, 125 | "schema": { 126 | "type": "integer" 127 | } 128 | } 129 | ], 130 | "responses": { 131 | "200": { 132 | "content": { 133 | "application/json": { 134 | "examples": { 135 | "response": { 136 | "value": [ 137 | { 138 | "id": 1, 139 | "message": "Hello World!" 140 | }, 141 | { 142 | "id": 2, 143 | "message": "Time is an illusion. Lunchtime doubly so." 144 | }, 145 | { 146 | "id": 3, 147 | "message": "So long, and thanks for all the fish." 148 | } 149 | ] 150 | } 151 | } 152 | } 153 | }, 154 | "description": "OK", 155 | "headers": {} 156 | } 157 | }, 158 | "summary": "Retrieve all Messages", 159 | "tags": [ 160 | "Messages" 161 | ] 162 | } 163 | } 164 | }, 165 | "servers": [], 166 | "tags": [ 167 | { 168 | "description": "Group of all messages-related resources.", 169 | "name": "Messages" 170 | } 171 | ] 172 | } 173 | -------------------------------------------------------------------------------- /test/output/openapi_3/regex_paths.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "title": "", 4 | "version": "" 5 | }, 6 | "openapi": "3.0.0", 7 | "paths": { 8 | "/{sessionId}": { 9 | "get": { 10 | "responses": { 11 | "200": { 12 | "description": "Successful Response" 13 | } 14 | } 15 | }, 16 | "parameters": [] 17 | }, 18 | "/{uuid}+{id}": { 19 | "get": { 20 | "responses": { 21 | "200": { 22 | "description": "Successful Response" 23 | } 24 | } 25 | }, 26 | "parameters": [] 27 | } 28 | }, 29 | "servers": [ 30 | { 31 | "url": "http://localhost:8080/resources/v1/" 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /test/output/openapi_3/sample_wadl.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "title": "", 4 | "version": "" 5 | }, 6 | "openapi": "3.0.0", 7 | "paths": { 8 | "/foo1": { 9 | "get": { 10 | "description": "- 200: OK\n- 204: method successfully executed but no content found with\n token\n- 400: bad request - check your parameters", 11 | "operationId": "getFoo1", 12 | "parameters": [ 13 | { 14 | "description": "a param", 15 | "in": "query", 16 | "name": "param1", 17 | "required": true, 18 | "schema": { 19 | "type": "string" 20 | } 21 | } 22 | ], 23 | "responses": { 24 | "200": { 25 | "description": "Successful Response" 26 | } 27 | } 28 | }, 29 | "parameters": [] 30 | }, 31 | "/sessions": { 32 | "parameters": [], 33 | "post": { 34 | "description": "create session\n- 201: session created", 35 | "operationId": "createSession", 36 | "responses": { 37 | "200": { 38 | "description": "Successful Response" 39 | } 40 | } 41 | } 42 | }, 43 | "/sessions/{sessionId}/event1": { 44 | "delete": { 45 | "description": "To notify that event1 is stopped\n- 204 : ok", 46 | "operationId": "event1Stopped", 47 | "responses": { 48 | "200": { 49 | "description": "Successful Response" 50 | } 51 | } 52 | }, 53 | "parameters": [ 54 | { 55 | "description": "session id", 56 | "in": "path", 57 | "name": "sessionId", 58 | "required": true, 59 | "schema": { 60 | "type": "string" 61 | } 62 | } 63 | ], 64 | "post": { 65 | "description": "To notify that event1 is started\n- 204 : ok", 66 | "operationId": "event1Started", 67 | "responses": { 68 | "200": { 69 | "description": "Successful Response" 70 | } 71 | } 72 | } 73 | }, 74 | "/sessions/{sessionId}/events": { 75 | "get": { 76 | "description": "Get events list starting from lastEventId. A session has to\n be created before\n- 200: OK\n- 204: method successfully executed but no event found\n- 400: bad request - check your parameters", 77 | "operationId": "getMediasAndEvents", 78 | "responses": { 79 | "200": { 80 | "description": "Successful Response" 81 | } 82 | } 83 | }, 84 | "parameters": [ 85 | { 86 | "description": "session id", 87 | "in": "path", 88 | "name": "sessionId", 89 | "required": true, 90 | "schema": { 91 | "type": "string" 92 | } 93 | }, 94 | { 95 | "description": "last event received, start with 0", 96 | "in": "query", 97 | "name": "lastEventId", 98 | "required": true, 99 | "schema": { 100 | "format": "int32", 101 | "type": "integer" 102 | } 103 | } 104 | ] 105 | }, 106 | "/sessions/{sessionId}/history": { 107 | "get": { 108 | "description": "Get session history\n- 200: OK\n- 204: method successfully executed but no history found\n- 400: bad request - check your parameters", 109 | "operationId": "getSHistory", 110 | "responses": { 111 | "200": { 112 | "description": "Successful Response" 113 | } 114 | } 115 | }, 116 | "parameters": [ 117 | { 118 | "description": "session id", 119 | "in": "path", 120 | "name": "sessionId", 121 | "required": true, 122 | "schema": { 123 | "type": "string" 124 | } 125 | } 126 | ] 127 | }, 128 | "/sessions/{sessionId}/type1/{CustomType2}": { 129 | "delete": { 130 | "description": "Stop event 2\n- 204: ok", 131 | "operationId": "stopEvent2", 132 | "responses": { 133 | "200": { 134 | "description": "Successful Response" 135 | } 136 | } 137 | }, 138 | "parameters": [ 139 | { 140 | "in": "path", 141 | "name": "sessionId", 142 | "required": true, 143 | "schema": { 144 | "type": "string" 145 | } 146 | }, 147 | { 148 | "in": "path", 149 | "name": "CustomType2", 150 | "required": true, 151 | "schema": { 152 | "type": "string" 153 | } 154 | } 155 | ], 156 | "put": { 157 | "description": "Event 2\n- 201: ok", 158 | "operationId": "event2", 159 | "responses": { 160 | "200": { 161 | "description": "Successful Response" 162 | } 163 | } 164 | } 165 | } 166 | }, 167 | "servers": [ 168 | { 169 | "url": "http://localhost:8080/resources/v1/" 170 | } 171 | ] 172 | } 173 | -------------------------------------------------------------------------------- /test/output/openapi_3/simplest.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "description": "This is one of the simplest APIs written in the **API Blueprint**.\nOne plain resource combined with a method and that's it! We will explain what is going on in the next installment - [Resource and Actions](02.%20Resource%20and%20Actions.md).\n\n**Note:** As we progress through the examples, do not also forget to view the [Raw](https://raw.github.com/apiaryio/api-blueprint/master/examples/01.%20Simplest%20API.md) code to see what is really going on in the API Blueprint, as opposed to just seeing the output of the Github Markdown parser.\n\nAlso please keep in mind that every single example in this course is a **real API Blueprint** and as such you can **parse** it with the [API Blueprint parser](https://github.com/apiaryio/drafter) or one of its [bindings](https://github.com/apiaryio/drafter#bindings).\n\n## API Blueprint\n\n+ [This: Raw API Blueprint](https://raw.github.com/apiaryio/api-blueprint/master/examples/01.%20Simplest%20API.md)\n\n+ [Next: Resource and Actions](02.%20Resource%20and%20Actions.md)", 4 | "title": "The Simplest API", 5 | "version": "" 6 | }, 7 | "openapi": "3.0.0", 8 | "paths": { 9 | "/message": { 10 | "get": { 11 | "description": "", 12 | "responses": { 13 | "200": { 14 | "content": { 15 | "text/plain": { 16 | "examples": { 17 | "response": { 18 | "value": "Hello World!\n" 19 | } 20 | } 21 | } 22 | }, 23 | "description": "OK", 24 | "headers": {} 25 | } 26 | }, 27 | "summary": "", 28 | "tags": [] 29 | } 30 | } 31 | }, 32 | "servers": [], 33 | "tags": [] 34 | } 35 | -------------------------------------------------------------------------------- /test/output/swagger_2/OpenStack_example.json: -------------------------------------------------------------------------------- 1 | { 2 | "basePath": "/", 3 | "host": "localhost:35357", 4 | "info": { 5 | "title": "", 6 | "version": "" 7 | }, 8 | "paths": { 9 | "/": { 10 | "get": { 11 | "operationId": "listVersions-v2", 12 | "responses": { 13 | "200": { 14 | "description": "Successful Response" 15 | } 16 | } 17 | }, 18 | "parameters": [] 19 | }, 20 | "/v2.0": { 21 | "get": { 22 | "operationId": "showVersionInfo-v2.0", 23 | "responses": { 24 | "200": { 25 | "description": "Successful Response" 26 | } 27 | } 28 | }, 29 | "parameters": [] 30 | }, 31 | "/v2.0/extensions": { 32 | "get": { 33 | "operationId": "listExtensions-v2", 34 | "responses": { 35 | "200": { 36 | "description": "Successful Response" 37 | } 38 | } 39 | }, 40 | "parameters": [] 41 | }, 42 | "/v2.0/extensions/{alias}": { 43 | "get": { 44 | "operationId": "showExtension-v2", 45 | "responses": { 46 | "200": { 47 | "description": "Successful Response" 48 | } 49 | } 50 | }, 51 | "parameters": [ 52 | { 53 | "in": "path", 54 | "name": "alias", 55 | "required": true, 56 | "type": "string" 57 | } 58 | ] 59 | }, 60 | "/v2.0/tenants": { 61 | "get": { 62 | "operationId": "listTenants", 63 | "parameters": [], 64 | "responses": { 65 | "200": { 66 | "description": "Successful Response" 67 | } 68 | } 69 | }, 70 | "parameters": [ 71 | { 72 | "in": "header", 73 | "name": "X-Auth-Token", 74 | "required": true, 75 | "type": "string" 76 | }, 77 | { 78 | "format": "int32", 79 | "in": "query", 80 | "name": "limit", 81 | "required": false, 82 | "type": "integer" 83 | }, 84 | { 85 | "in": "query", 86 | "name": "marker", 87 | "required": false, 88 | "type": "string" 89 | } 90 | ] 91 | }, 92 | "/v2.0/tokens": { 93 | "parameters": [], 94 | "post": { 95 | "operationId": "authenticate-v2.0", 96 | "parameters": [], 97 | "responses": { 98 | "200": { 99 | "description": "Successful Response" 100 | } 101 | } 102 | } 103 | } 104 | }, 105 | "schemes": [ 106 | "http" 107 | ], 108 | "swagger": "2.0" 109 | } 110 | -------------------------------------------------------------------------------- /test/output/swagger_2/XKCD.json: -------------------------------------------------------------------------------- 1 | { 2 | "basePath": "/", 3 | "definitions": { 4 | "comic": { 5 | "properties": { 6 | "alt": { 7 | "type": "string" 8 | }, 9 | "day": { 10 | "type": "string" 11 | }, 12 | "img": { 13 | "type": "string" 14 | }, 15 | "link": { 16 | "type": "string" 17 | }, 18 | "month": { 19 | "type": "string" 20 | }, 21 | "news": { 22 | "type": "string" 23 | }, 24 | "num": { 25 | "type": "number" 26 | }, 27 | "safe_title": { 28 | "type": "string" 29 | }, 30 | "title": { 31 | "type": "string" 32 | }, 33 | "transcript": { 34 | "type": "string" 35 | }, 36 | "year": { 37 | "type": "string" 38 | } 39 | }, 40 | "type": "object" 41 | } 42 | }, 43 | "host": "xkcd.com", 44 | "info": { 45 | "title": "XKCD", 46 | "version": "< An API version here >" 47 | }, 48 | "paths": { 49 | "/info.0.json": { 50 | "get": { 51 | "description": "Fetch current comic and metadata.\n", 52 | "responses": { 53 | "200": { 54 | "description": "OK", 55 | "schema": { 56 | "$ref": "#/definitions/comic" 57 | } 58 | } 59 | } 60 | } 61 | }, 62 | "/{comicId}/info.0.json": { 63 | "get": { 64 | "description": "Fetch comics and metadata by comic id.\n", 65 | "parameters": [ 66 | { 67 | "in": "path", 68 | "name": "comicId", 69 | "required": true, 70 | "type": "string" 71 | } 72 | ], 73 | "responses": { 74 | "200": { 75 | "description": "OK", 76 | "schema": { 77 | "$ref": "#/definitions/comic" 78 | } 79 | } 80 | } 81 | } 82 | } 83 | }, 84 | "schemes": [ 85 | "http" 86 | ], 87 | "securityDefinitions": {}, 88 | "swagger": "2.0" 89 | } 90 | -------------------------------------------------------------------------------- /test/output/swagger_2/common_params.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "title": "testcommonparams", 4 | "version": "0.0.1" 5 | }, 6 | "paths": { 7 | "/resource/{id}": { 8 | "parameters": [ 9 | { 10 | "in": "path", 11 | "name": "id", 12 | "type": "integer", 13 | "x-example": 0 14 | }, 15 | { 16 | "name": "name" 17 | } 18 | ] 19 | } 20 | }, 21 | "swagger": "2.0" 22 | } 23 | -------------------------------------------------------------------------------- /test/output/swagger_2/deprecated.yml: -------------------------------------------------------------------------------- 1 | { 2 | "definitions": { 3 | "Schema1": { 4 | "properties": { 5 | "prop1": { 6 | "type": "string", 7 | "x-deprecated": { 8 | "description": "Prop deprecation info" 9 | } 10 | }, 11 | "prop2": { 12 | "type": "string", 13 | "x-deprecated": { 14 | "description": "Prop also deprecated" 15 | } 16 | }, 17 | "prop3": { 18 | "type": "integer", 19 | "x-deprecated": false 20 | } 21 | }, 22 | "type": "object", 23 | "x-deprecated": true 24 | }, 25 | "Schema2": { 26 | "properties": { 27 | "prop4": { 28 | "type": "string", 29 | "x-deprecated": true 30 | }, 31 | "prop5": { 32 | "items": { 33 | "type": "string", 34 | "x-deprecated": true 35 | }, 36 | "type": "array" 37 | } 38 | }, 39 | "type": "object", 40 | "x-deprecated": { 41 | "replaced-by": "Schema1" 42 | } 43 | }, 44 | "Schema3": { 45 | "items": { 46 | "type": "string" 47 | }, 48 | "type": "array", 49 | "x-deprecated": false 50 | } 51 | }, 52 | "info": { 53 | "title": "API with deprecated schemas and operations\nSee https://github.com/Azure/autorest/tree/master/Samples/test/deprecated for description of x-deprecated as supported by Autorest", 54 | "version": "0.0.1" 55 | }, 56 | "paths": { 57 | "/path1": { 58 | "get": { 59 | "deprecated": true, 60 | "operationId": "getPath1", 61 | "parameters": [], 62 | "produces": [ 63 | "application/json" 64 | ], 65 | "responses": { 66 | "200": { 67 | "description": "Deprecated operation 1", 68 | "schema": { 69 | "$ref": "#/definitions/Schema1" 70 | } 71 | } 72 | } 73 | } 74 | }, 75 | "/path2": { 76 | "get": { 77 | "deprecated": true, 78 | "operationId": "getPath2", 79 | "parameters": [], 80 | "produces": [ 81 | "application/json" 82 | ], 83 | "responses": { 84 | "200": { 85 | "description": "Deprecated operation 2", 86 | "schema": { 87 | "$ref": "#/definitions/Schema2" 88 | } 89 | } 90 | }, 91 | "x-deprecated": { 92 | "description": "Deprecation info" 93 | } 94 | } 95 | }, 96 | "/path3": { 97 | "get": { 98 | "operationId": "getPath3", 99 | "parameters": [], 100 | "produces": [ 101 | "application/json" 102 | ], 103 | "responses": { 104 | "200": { 105 | "description": "Operation 3", 106 | "schema": { 107 | "$ref": "#/definitions/Schema3" 108 | } 109 | } 110 | } 111 | } 112 | } 113 | }, 114 | "swagger": "2.0", 115 | "x-components": {} 116 | } 117 | -------------------------------------------------------------------------------- /test/output/swagger_2/form_param.yml: -------------------------------------------------------------------------------- 1 | definitions: 2 | ImageFormat: 3 | enum: 4 | - gif 5 | - jpeg 6 | - png 7 | type: string 8 | x-ms-enum: 9 | modelAsString: true 10 | name: ImageType 11 | info: 12 | title: test 13 | version: 0.0.1 14 | paths: 15 | /foo: 16 | post: 17 | consumes: 18 | - multipart/form-data 19 | operationId: getFoo 20 | parameters: 21 | - in: formData 22 | name: name 23 | type: string 24 | - enum: 25 | - gif 26 | - jpeg 27 | - png 28 | in: formData 29 | name: format 30 | type: string 31 | x-ms-enum: 32 | modelAsString: true 33 | name: ImageType 34 | - format: binary 35 | in: formData 36 | name: image 37 | required: true 38 | type: string 39 | produces: 40 | - application/json 41 | responses: 42 | '200': 43 | description: Foo 44 | schema: 45 | type: object 46 | tags: 47 | - Foos 48 | swagger: '2.0' 49 | x-components: {} 50 | 51 | -------------------------------------------------------------------------------- /test/output/swagger_2/has_external_ref.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "title": "Nodejs", 4 | "version": "1.0.0" 5 | }, 6 | "paths": { 7 | "/articles": { 8 | "get": { 9 | "operationId": "ArticleController.getAll", 10 | "parameters": [], 11 | "produces": [ 12 | "application/json" 13 | ], 14 | "responses": { 15 | "200": { 16 | "description": "Successful response", 17 | "schema": { 18 | "type": "string" 19 | } 20 | }, 21 | "default": { 22 | "description": "Error response" 23 | } 24 | }, 25 | "summary": "Get all", 26 | "tags": [ 27 | "Article" 28 | ] 29 | } 30 | } 31 | }, 32 | "swagger": "2.0" 33 | } 34 | -------------------------------------------------------------------------------- /test/output/swagger_2/klout.json: -------------------------------------------------------------------------------- 1 | { 2 | "basePath": "/v2", 3 | "host": [ 4 | "api.klout.com" 5 | ], 6 | "info": { 7 | "title": "Partner API v2", 8 | "version": "< An API version here >" 9 | }, 10 | "paths": { 11 | "/identity.json/gp/{google_plus_id}": { 12 | "get": { 13 | "parameters": [ 14 | { 15 | "default": "112620727907435773834", 16 | "description": "A Google+ ID (e.g. 112620727907435773834)", 17 | "in": "path", 18 | "name": "google_plus_id", 19 | "type": "string" 20 | } 21 | ], 22 | "responses": { 23 | "200": { 24 | "description": "success" 25 | } 26 | } 27 | } 28 | }, 29 | "/identity.json/ig/{instagram_id}": { 30 | "get": { 31 | "parameters": [ 32 | { 33 | "default": "816029", 34 | "description": "An Instagram ID (e.g. 816029)", 35 | "in": "path", 36 | "name": "instagram_id", 37 | "type": "string" 38 | } 39 | ], 40 | "responses": { 41 | "200": { 42 | "description": "success" 43 | } 44 | } 45 | } 46 | }, 47 | "/identity.json/klout/{klout_id}/tw": { 48 | "get": { 49 | "parameters": [ 50 | { 51 | "default": "635263", 52 | "description": "A KloutId (like 635263)", 53 | "in": "path", 54 | "name": "klout_id", 55 | "type": "string" 56 | } 57 | ], 58 | "responses": { 59 | "200": { 60 | "description": "success" 61 | } 62 | } 63 | } 64 | }, 65 | "/identity.json/tw/{twitter_id}": { 66 | "get": { 67 | "parameters": [ 68 | { 69 | "default": "500042487", 70 | "description": "A twitter ID (e.g. 500042487)", 71 | "in": "query", 72 | "name": "twitter_id", 73 | "type": "string" 74 | } 75 | ], 76 | "responses": { 77 | "200": { 78 | "description": "success" 79 | } 80 | } 81 | } 82 | }, 83 | "/identity.json/twitter": { 84 | "get": { 85 | "parameters": [ 86 | { 87 | "default": "jtimberlake", 88 | "description": "A twitter screen name (e.g. jtimberlake)", 89 | "in": "query", 90 | "name": "screenName", 91 | "type": "string" 92 | } 93 | ], 94 | "responses": { 95 | "200": { 96 | "description": "success" 97 | } 98 | } 99 | } 100 | }, 101 | "/user.json/{kloutId}": { 102 | "get": { 103 | "parameters": [ 104 | { 105 | "default": "635263", 106 | "description": "A kloutId (like 635263)", 107 | "in": "path", 108 | "name": "kloutId", 109 | "type": "string" 110 | } 111 | ], 112 | "responses": { 113 | "200": { 114 | "description": "success" 115 | } 116 | } 117 | } 118 | }, 119 | "/user.json/{kloutId}/influence": { 120 | "get": { 121 | "parameters": [ 122 | { 123 | "default": "635263", 124 | "description": "A kloutId (like 635263)", 125 | "in": "path", 126 | "name": "kloutId", 127 | "type": "string" 128 | } 129 | ], 130 | "responses": { 131 | "200": { 132 | "description": "success" 133 | } 134 | } 135 | } 136 | }, 137 | "/user.json/{kloutId}/score": { 138 | "get": { 139 | "parameters": [ 140 | { 141 | "default": "635263", 142 | "description": "A kloutId (like 635263)", 143 | "in": "path", 144 | "name": "kloutId", 145 | "type": "string" 146 | } 147 | ], 148 | "responses": { 149 | "200": { 150 | "description": "success" 151 | } 152 | } 153 | } 154 | }, 155 | "/user.json/{kloutId}/topics": { 156 | "get": { 157 | "parameters": [ 158 | { 159 | "default": "635263", 160 | "description": "A kloutId (like 635263)", 161 | "in": "path", 162 | "name": "kloutId", 163 | "type": "string" 164 | } 165 | ], 166 | "responses": { 167 | "200": { 168 | "description": "success" 169 | } 170 | } 171 | } 172 | } 173 | }, 174 | "schemes": [ 175 | "http:" 176 | ], 177 | "swagger": "2.0" 178 | } 179 | -------------------------------------------------------------------------------- /test/output/swagger_2/minimal.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "title": "Nodejs", 4 | "version": "1.0.0" 5 | }, 6 | "paths": { 7 | "/articles": { 8 | "get": { 9 | "operationId": "ArticleController.getAll", 10 | "parameters": [], 11 | "produces": [ 12 | "application/json" 13 | ], 14 | "responses": { 15 | "200": { 16 | "description": "Successful response" 17 | } 18 | }, 19 | "summary": "Get all", 20 | "tags": [ 21 | "Article" 22 | ] 23 | } 24 | } 25 | }, 26 | "swagger": "2.0" 27 | } 28 | -------------------------------------------------------------------------------- /test/output/swagger_2/multiple_ref.json: -------------------------------------------------------------------------------- 1 | { 2 | "basePath": "/", 3 | "host": "somewhere.test", 4 | "info": { 5 | "description": "test", 6 | "title": "test", 7 | "version": "2" 8 | }, 9 | "paths": { 10 | "/testBodyRefIsResolved": { 11 | "post": { 12 | "consumes": [ 13 | "application/json" 14 | ], 15 | "description": "test", 16 | "parameters": [ 17 | { 18 | "description": "Some content", 19 | "in": "body", 20 | "name": "body", 21 | "required": true, 22 | "schema": { 23 | "example": {}, 24 | "type": "object" 25 | } 26 | } 27 | ], 28 | "responses": { 29 | "200": { 30 | "description": "ok" 31 | } 32 | }, 33 | "summary": "test" 34 | } 35 | }, 36 | "/testSameBodyRefIsResolvedAgain": { 37 | "post": { 38 | "consumes": [ 39 | "application/json" 40 | ], 41 | "description": "test", 42 | "parameters": [ 43 | { 44 | "description": "Some content", 45 | "in": "body", 46 | "name": "body", 47 | "required": true, 48 | "schema": { 49 | "example": {}, 50 | "type": "object" 51 | } 52 | } 53 | ], 54 | "responses": { 55 | "200": { 56 | "description": "ok" 57 | } 58 | }, 59 | "summary": "test" 60 | } 61 | } 62 | }, 63 | "schemes": [ 64 | "https" 65 | ], 66 | "swagger": "2.0", 67 | "x-components": { 68 | "requestBodies": { 69 | "Value": { 70 | "content": { 71 | "application/json": { 72 | "schema": { 73 | "example": {}, 74 | "type": "object" 75 | } 76 | } 77 | }, 78 | "description": "Some content", 79 | "required": true 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /test/output/swagger_2/nested_oneof.yml: -------------------------------------------------------------------------------- 1 | definitions: 2 | Foo: 3 | properties: 4 | bar: {} 5 | type: object 6 | OtherBar: 7 | properties: 8 | other: 9 | type: string 10 | type: object 11 | SomeBar: 12 | type: string 13 | info: 14 | title: test 15 | version: 0.0.1 16 | paths: 17 | /foo: 18 | get: 19 | operationId: getFoo 20 | parameters: [] 21 | produces: 22 | - application/hal+json 23 | responses: 24 | '200': 25 | description: Foo 26 | schema: 27 | $ref: '#/definitions/Foo' 28 | tags: 29 | - Foos 30 | swagger: '2.0' 31 | x-components: {} 32 | 33 | -------------------------------------------------------------------------------- /test/output/swagger_2/nullable.yml: -------------------------------------------------------------------------------- 1 | definitions: 2 | Foo: 3 | type: string 4 | x-nullable: true 5 | info: 6 | title: test 7 | version: 0.0.1 8 | paths: 9 | /foo: 10 | get: 11 | operationId: getFoo 12 | parameters: [] 13 | produces: 14 | - application/hal+json 15 | responses: 16 | '200': 17 | description: Foo 18 | schema: 19 | $ref: '#/definitions/Foo' 20 | tags: 21 | - Foos 22 | swagger: '2.0' 23 | x-components: {} 24 | 25 | -------------------------------------------------------------------------------- /test/output/swagger_2/param_schema_ref.json: -------------------------------------------------------------------------------- 1 | { 2 | "definitions": { 3 | "DefaultResponseObject": { 4 | "properties": { 5 | "message": { 6 | "type": "string" 7 | } 8 | }, 9 | "required": [ 10 | "message" 11 | ] 12 | }, 13 | "accountLevel": { 14 | "enum": [ 15 | "one", 16 | "two", 17 | "three", 18 | "four" 19 | ], 20 | "type": "string" 21 | } 22 | }, 23 | "info": { 24 | "title": "testsickle", 25 | "version": "0.0.1" 26 | }, 27 | "paths": { 28 | "/user/account/{accountLevel}": { 29 | "post": { 30 | "parameters": [ 31 | { 32 | "enum": [ 33 | "one", 34 | "two", 35 | "three", 36 | "four" 37 | ], 38 | "in": "path", 39 | "name": "accountLevel", 40 | "required": true, 41 | "type": "string" 42 | } 43 | ], 44 | "produces": [ 45 | "application/json" 46 | ], 47 | "responses": { 48 | "200": { 49 | "description": "Success", 50 | "schema": { 51 | "$ref": "#/definitions/DefaultResponseObject" 52 | } 53 | } 54 | } 55 | } 56 | } 57 | }, 58 | "swagger": "2.0", 59 | "x-components": { 60 | "responses": { 61 | "defaultResponse": { 62 | "content": { 63 | "application/json": { 64 | "schema": { 65 | "$ref": "#/definitions/DefaultResponseObject" 66 | } 67 | } 68 | }, 69 | "description": "Success" 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /test/output/swagger_2/param_schema_unordered_ref.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "title": "testsickle", 4 | "version": "0.0.1" 5 | }, 6 | "paths": { 7 | "/user/account/{accountLevel}": { 8 | "post": { 9 | "parameters": [ 10 | { 11 | "in": "path", 12 | "name": "accountLevel", 13 | "required": true, 14 | "enum": [ 15 | "one", 16 | "two", 17 | "three", 18 | "four" 19 | ], 20 | "type": "string" 21 | } 22 | ], 23 | "responses": { 24 | "200": { 25 | "description": "Success", 26 | "schema": { 27 | "$ref": "#/definitions/DefaultResponseObject" 28 | } 29 | } 30 | }, 31 | "produces": [ 32 | "application/json" 33 | ] 34 | } 35 | } 36 | }, 37 | "swagger": "2.0", 38 | "definitions": { 39 | "accountLevel": { 40 | "type": "string", 41 | "enum": [ 42 | "one", 43 | "two", 44 | "three", 45 | "four" 46 | ] 47 | }, 48 | "DefaultResponseObject": { 49 | "required": [ 50 | "message" 51 | ], 52 | "properties": { 53 | "message": { 54 | "type": "string" 55 | } 56 | } 57 | } 58 | }, 59 | "x-components": { 60 | "responses": { 61 | "defaultResponse": { 62 | "description": "Success", 63 | "content": { 64 | "application/json": { 65 | "schema": { 66 | "$ref": "#/definitions/DefaultResponseObject" 67 | } 68 | } 69 | } 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /test/output/swagger_2/parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "definitions": { 3 | "All My Messages": {}, 4 | "My Message": {} 5 | }, 6 | "info": { 7 | "description": "In this installment of the API Blueprint course we will discuss how to describe URI parameters.\n\nBut first let's add more messages to our system. For that we would need introduce an message identifier – id. This id will be our parameter when communicating with our API about messages.\n\n## API Blueprint\n\n+ [Previous: Requests](06.%20Requests.md)\n\n+ [This: Raw API Blueprint](https://raw.github.com/apiaryio/api-blueprint/master/examples/07.%20Parameters.md)\n\n+ [Next: Attributes](08.%20Attributes.md)", 8 | "title": "Parameters API", 9 | "version": "" 10 | }, 11 | "paths": { 12 | "/message/{id}": { 13 | "get": { 14 | "description": "", 15 | "parameters": [ 16 | { 17 | "description": "An unique identifier of the message.", 18 | "in": "path", 19 | "name": "id", 20 | "required": true, 21 | "type": "number", 22 | "x-example": "1" 23 | }, 24 | { 25 | "description": "e.g. text/plain", 26 | "in": "header", 27 | "name": "Accept", 28 | "required": false, 29 | "type": "string", 30 | "x-example": "text/plain" 31 | } 32 | ], 33 | "produces": [ 34 | "application/json" 35 | ], 36 | "responses": { 37 | "200": { 38 | "description": "OK", 39 | "examples": { 40 | "application/json": { 41 | "id": 1, 42 | "message": "Hello World!" 43 | } 44 | }, 45 | "headers": {} 46 | } 47 | }, 48 | "summary": "Retrieve a Message", 49 | "tags": [ 50 | "Messages" 51 | ] 52 | }, 53 | "put": { 54 | "description": "", 55 | "parameters": [ 56 | { 57 | "description": "An unique identifier of the message.", 58 | "in": "path", 59 | "name": "id", 60 | "required": true, 61 | "type": "number", 62 | "x-example": "1" 63 | }, 64 | { 65 | "in": "body", 66 | "name": "body", 67 | "schema": { 68 | "example": { 69 | "message": "All your base are belong to us." 70 | }, 71 | "properties": { 72 | "message": { 73 | "type": "string" 74 | } 75 | }, 76 | "type": "object" 77 | } 78 | } 79 | ], 80 | "responses": { 81 | "204": { 82 | "description": "No Content", 83 | "examples": {}, 84 | "headers": {} 85 | } 86 | }, 87 | "summary": "Update a Message", 88 | "tags": [ 89 | "Messages" 90 | ] 91 | } 92 | }, 93 | "/messages": { 94 | "get": { 95 | "description": "", 96 | "parameters": [ 97 | { 98 | "default": 20, 99 | "description": "The maximum number of results to return.", 100 | "in": "query", 101 | "name": "limit", 102 | "required": false, 103 | "type": "number" 104 | }, 105 | { 106 | "description": "Which page of results to return", 107 | "in": "query", 108 | "name": "page", 109 | "required": false, 110 | "type": "integer" 111 | } 112 | ], 113 | "produces": [ 114 | "application/json" 115 | ], 116 | "responses": { 117 | "200": { 118 | "description": "OK", 119 | "examples": { 120 | "application/json": [ 121 | { 122 | "id": 1, 123 | "message": "Hello World!" 124 | }, 125 | { 126 | "id": 2, 127 | "message": "Time is an illusion. Lunchtime doubly so." 128 | }, 129 | { 130 | "id": 3, 131 | "message": "So long, and thanks for all the fish." 132 | } 133 | ] 134 | }, 135 | "headers": {} 136 | } 137 | }, 138 | "summary": "Retrieve all Messages", 139 | "tags": [ 140 | "Messages" 141 | ] 142 | } 143 | } 144 | }, 145 | "securityDefinitions": {}, 146 | "swagger": "2.0", 147 | "tags": [ 148 | { 149 | "description": "Group of all messages-related resources.", 150 | "name": "Messages" 151 | } 152 | ] 153 | } 154 | -------------------------------------------------------------------------------- /test/output/swagger_2/produces.json: -------------------------------------------------------------------------------- 1 | { 2 | "definitions": { 3 | "Foo": { 4 | "type": "string" 5 | }, 6 | "Problem": { 7 | "type": "string" 8 | } 9 | }, 10 | "info": { 11 | "title": "test", 12 | "version": "0.0.1" 13 | }, 14 | "paths": { 15 | "/foo": { 16 | "get": { 17 | "operationId": "getFoo", 18 | "parameters": [], 19 | "produces": [ 20 | "application/hal+json", 21 | "application/problem+json" 22 | ], 23 | "responses": { 24 | "200": { 25 | "description": "Foo", 26 | "schema": { 27 | "$ref": "#/definitions/Foo" 28 | } 29 | }, 30 | "default": { 31 | "description": "Unexpected problem", 32 | "schema": { 33 | "$ref": "#/definitions/Problem" 34 | } 35 | } 36 | }, 37 | "tags": [ 38 | "Foos" 39 | ] 40 | } 41 | } 42 | }, 43 | "swagger": "2.0", 44 | "x-components": {} 45 | } 46 | -------------------------------------------------------------------------------- /test/output/swagger_2/regex_paths.json: -------------------------------------------------------------------------------- 1 | { 2 | "basePath": "/resources/v1/", 3 | "host": "localhost:8080", 4 | "info": { 5 | "title": "", 6 | "version": "" 7 | }, 8 | "paths": { 9 | "/{sessionId}": { 10 | "get": { 11 | "responses": { 12 | "200": { 13 | "description": "Successful Response" 14 | } 15 | } 16 | }, 17 | "parameters": [] 18 | }, 19 | "/{uuid}+{id}": { 20 | "get": { 21 | "responses": { 22 | "200": { 23 | "description": "Successful Response" 24 | } 25 | } 26 | }, 27 | "parameters": [] 28 | } 29 | }, 30 | "schemes": [ 31 | "http" 32 | ], 33 | "swagger": "2.0" 34 | } 35 | -------------------------------------------------------------------------------- /test/output/swagger_2/request_response_ref.yml: -------------------------------------------------------------------------------- 1 | definitions: 2 | PetName: 3 | properties: 4 | name: 5 | type: string 6 | nickname: 7 | type: string 8 | x-nullable: true 9 | type: object 10 | info: 11 | title: test 12 | version: 0.0.1 13 | paths: 14 | /foo: 15 | post: 16 | consumes: 17 | - application/json 18 | operationId: getFoo 19 | parameters: 20 | - in: body 21 | name: body 22 | required: true 23 | schema: 24 | properties: 25 | name: 26 | type: string 27 | x-nullable: true 28 | pet: 29 | allOf: 30 | - $ref: '#/definitions/PetName' 31 | - properties: 32 | favorite_foods: 33 | items: 34 | type: string 35 | x-nullable: true 36 | type: array 37 | type: object 38 | type: object 39 | produces: 40 | - application/json 41 | responses: 42 | '200': 43 | description: Foo 44 | schema: 45 | allOf: 46 | - $ref: '#/definitions/PetName' 47 | - properties: 48 | name: 49 | type: string 50 | x-nullable: true 51 | type: object 52 | tags: 53 | - Foos 54 | swagger: '2.0' 55 | x-components: 56 | requestBodies: 57 | FooRequest: 58 | content: 59 | application/json: 60 | schema: 61 | properties: 62 | name: 63 | nullable: true 64 | type: string 65 | pet: 66 | allOf: 67 | - $ref: '#/definitions/PetName' 68 | - properties: 69 | favorite_foods: 70 | items: 71 | nullable: true 72 | type: string 73 | type: array 74 | type: object 75 | type: object 76 | required: true 77 | responses: 78 | FooResponse: 79 | content: 80 | application/json: 81 | schema: 82 | allOf: 83 | - $ref: '#/definitions/PetName' 84 | - properties: 85 | name: 86 | nullable: true 87 | type: string 88 | type: object 89 | description: Foo 90 | 91 | -------------------------------------------------------------------------------- /test/output/swagger_2/sample_wadl.json: -------------------------------------------------------------------------------- 1 | { 2 | "basePath": "/resources/v1/", 3 | "host": "localhost:8080", 4 | "info": { 5 | "title": "", 6 | "version": "" 7 | }, 8 | "paths": { 9 | "/foo1": { 10 | "get": { 11 | "description": "- 200: OK\n- 204: method successfully executed but no content found with\n token\n- 400: bad request - check your parameters", 12 | "operationId": "getFoo1", 13 | "parameters": [ 14 | { 15 | "description": "a param", 16 | "in": "query", 17 | "name": "param1", 18 | "required": true, 19 | "type": "string" 20 | } 21 | ], 22 | "responses": { 23 | "200": { 24 | "description": "Successful Response" 25 | } 26 | } 27 | }, 28 | "parameters": [] 29 | }, 30 | "/sessions": { 31 | "parameters": [], 32 | "post": { 33 | "description": "create session\n- 201: session created", 34 | "operationId": "createSession", 35 | "parameters": [], 36 | "responses": { 37 | "200": { 38 | "description": "Successful Response" 39 | } 40 | } 41 | } 42 | }, 43 | "/sessions/{sessionId}/event1": { 44 | "delete": { 45 | "description": "To notify that event1 is stopped\n- 204 : ok", 46 | "operationId": "event1Stopped", 47 | "parameters": [], 48 | "responses": { 49 | "200": { 50 | "description": "Successful Response" 51 | } 52 | } 53 | }, 54 | "parameters": [ 55 | { 56 | "description": "session id", 57 | "in": "path", 58 | "name": "sessionId", 59 | "required": true, 60 | "type": "string" 61 | } 62 | ], 63 | "post": { 64 | "description": "To notify that event1 is started\n- 204 : ok", 65 | "operationId": "event1Started", 66 | "parameters": [], 67 | "responses": { 68 | "200": { 69 | "description": "Successful Response" 70 | } 71 | } 72 | } 73 | }, 74 | "/sessions/{sessionId}/events": { 75 | "get": { 76 | "description": "Get events list starting from lastEventId. A session has to\n be created before\n- 200: OK\n- 204: method successfully executed but no event found\n- 400: bad request - check your parameters", 77 | "operationId": "getMediasAndEvents", 78 | "parameters": [], 79 | "responses": { 80 | "200": { 81 | "description": "Successful Response" 82 | } 83 | } 84 | }, 85 | "parameters": [ 86 | { 87 | "description": "session id", 88 | "in": "path", 89 | "name": "sessionId", 90 | "required": true, 91 | "type": "string" 92 | }, 93 | { 94 | "description": "last event received, start with 0", 95 | "format": "int32", 96 | "in": "query", 97 | "name": "lastEventId", 98 | "required": true, 99 | "type": "integer" 100 | } 101 | ] 102 | }, 103 | "/sessions/{sessionId}/history": { 104 | "get": { 105 | "description": "Get session history\n- 200: OK\n- 204: method successfully executed but no history found\n- 400: bad request - check your parameters", 106 | "operationId": "getSHistory", 107 | "parameters": [], 108 | "responses": { 109 | "200": { 110 | "description": "Successful Response" 111 | } 112 | } 113 | }, 114 | "parameters": [ 115 | { 116 | "description": "session id", 117 | "in": "path", 118 | "name": "sessionId", 119 | "required": true, 120 | "type": "string" 121 | } 122 | ] 123 | }, 124 | "/sessions/{sessionId}/type1/{CustomType2}": { 125 | "delete": { 126 | "description": "Stop event 2\n- 204: ok", 127 | "operationId": "stopEvent2", 128 | "parameters": [], 129 | "responses": { 130 | "200": { 131 | "description": "Successful Response" 132 | } 133 | } 134 | }, 135 | "parameters": [ 136 | { 137 | "in": "path", 138 | "name": "sessionId", 139 | "required": true, 140 | "type": "string" 141 | }, 142 | { 143 | "in": "path", 144 | "name": "CustomType2", 145 | "required": true, 146 | "type": "string" 147 | } 148 | ], 149 | "put": { 150 | "description": "Event 2\n- 201: ok", 151 | "operationId": "event2", 152 | "parameters": [], 153 | "responses": { 154 | "200": { 155 | "description": "Successful Response" 156 | } 157 | } 158 | } 159 | } 160 | }, 161 | "schemes": [ 162 | "http" 163 | ], 164 | "swagger": "2.0" 165 | } 166 | -------------------------------------------------------------------------------- /test/output/swagger_2/servers.json: -------------------------------------------------------------------------------- 1 | { 2 | "basePath": "/api", 3 | "host": "api.example.com", 4 | "info": { 5 | "description": "API description in Markdown.", 6 | "title": "Sample API", 7 | "version": "1.0.0" 8 | }, 9 | "schemes": [ 10 | "https" 11 | ], 12 | "swagger": "2.0" 13 | } 14 | -------------------------------------------------------------------------------- /test/output/swagger_2/simplest.json: -------------------------------------------------------------------------------- 1 | { 2 | "definitions": {}, 3 | "info": { 4 | "description": "This is one of the simplest APIs written in the **API Blueprint**.\nOne plain resource combined with a method and that's it! We will explain what is going on in the next installment - [Resource and Actions](02.%20Resource%20and%20Actions.md).\n\n**Note:** As we progress through the examples, do not also forget to view the [Raw](https://raw.github.com/apiaryio/api-blueprint/master/examples/01.%20Simplest%20API.md) code to see what is really going on in the API Blueprint, as opposed to just seeing the output of the Github Markdown parser.\n\nAlso please keep in mind that every single example in this course is a **real API Blueprint** and as such you can **parse** it with the [API Blueprint parser](https://github.com/apiaryio/drafter) or one of its [bindings](https://github.com/apiaryio/drafter#bindings).\n\n## API Blueprint\n\n+ [This: Raw API Blueprint](https://raw.github.com/apiaryio/api-blueprint/master/examples/01.%20Simplest%20API.md)\n\n+ [Next: Resource and Actions](02.%20Resource%20and%20Actions.md)", 5 | "title": "The Simplest API", 6 | "version": "" 7 | }, 8 | "paths": { 9 | "/message": { 10 | "get": { 11 | "description": "", 12 | "parameters": [], 13 | "produces": [ 14 | "text/plain" 15 | ], 16 | "responses": { 17 | "200": { 18 | "description": "OK", 19 | "examples": { 20 | "text/plain": "Hello World!\n" 21 | }, 22 | "headers": {} 23 | } 24 | }, 25 | "summary": "", 26 | "tags": [] 27 | } 28 | } 29 | }, 30 | "securityDefinitions": {}, 31 | "swagger": "2.0", 32 | "tags": [] 33 | } 34 | -------------------------------------------------------------------------------- /test/output/swagger_2/slash_ref.json: -------------------------------------------------------------------------------- 1 | { 2 | "basePath": "/", 3 | "host": "api.example.com", 4 | "info": { 5 | "description": "API description in Markdown.", 6 | "title": "Sample API", 7 | "version": "1.0.0" 8 | }, 9 | "paths": { 10 | "/other_users": { 11 | "get": { 12 | "description": "Optional extended description in Markdown.", 13 | "parameters": [], 14 | "responses": { 15 | "200": { 16 | "description": "OK" 17 | } 18 | }, 19 | "summary": "Returns a list of users." 20 | } 21 | }, 22 | "/users~": { 23 | "get": { 24 | "description": "Optional extended description in Markdown.", 25 | "parameters": [], 26 | "responses": { 27 | "200": { 28 | "description": "OK" 29 | } 30 | }, 31 | "summary": "Returns a list of users." 32 | } 33 | } 34 | }, 35 | "schemes": [ 36 | "https" 37 | ], 38 | "swagger": "2.0" 39 | } 40 | -------------------------------------------------------------------------------- /test/output/swagger_2/yaml_with_ref.yml: -------------------------------------------------------------------------------- 1 | info: 2 | title: testsickle 3 | version: 0.0.1 4 | paths: 5 | '/api/v2/user/{id}': 6 | get: 7 | operationId: user.get 8 | parameters: 9 | - in: path 10 | name: id 11 | type: string 12 | summary: Get user 13 | tags: 14 | - User 15 | swagger: '2.0' 16 | 17 | -------------------------------------------------------------------------------- /test/setup/browser.js: -------------------------------------------------------------------------------- 1 | var host = location.protocol+'//'+location.hostname+(location.port ? ':'+location.port: '') 2 | 3 | window.getFileName = function(dir, testCaseItem) { 4 | var file = testCaseItem.format; 5 | if (testCaseItem.directory) file += '/' + testCaseItem.directory; 6 | file += '/' + testCaseItem.file; 7 | return host + '/test/' + dir + '/' + file; 8 | } 9 | 10 | // returns file content as a JavaScript 11 | window.getFile = function(file, cb) { 12 | var xobj = new XMLHttpRequest(); 13 | xobj.open('GET', file, true); 14 | xobj.onload = function () { 15 | // TODO: handle YAML 16 | if (xobj.status === 200) 17 | cb(null, JSON.parse(xobj.response)); 18 | else 19 | cb(Error(xobj.status + ': Failed to load ' + file)); 20 | }; 21 | xobj.send(null); 22 | } 23 | 24 | // returns file content as a string 25 | window.getFileRaw = function(file, cb) { 26 | var xobj = new XMLHttpRequest(); 27 | xobj.open('GET', file, true); 28 | xobj.onload = function () { 29 | if (xobj.status === 200) 30 | cb(null, xobj.response); 31 | else 32 | cb(Error(xobj.status + ': Failed to load ' + file)); 33 | }; 34 | xobj.send(null); 35 | } 36 | 37 | window.WRITE_GOLDEN = false; 38 | window.expect = window.chai.expect; 39 | window.Converter = APISpecConverter; 40 | -------------------------------------------------------------------------------- /test/setup/node.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var path = require('path'); 3 | var YAML = require('js-yaml'); 4 | 5 | global.getFileName = function(dir, testCase) { 6 | return path.join(__dirname, '..', dir, testCase.format, testCase.directory || '', testCase.file); 7 | } 8 | 9 | // returns file content as a JavaScript 10 | global.getFile = function(file, cb) { 11 | var content = fs.readFileSync(file, 'utf8'); 12 | var parsed = file.endsWith('json') ? JSON.parse(content) : YAML.safeLoad(content); 13 | cb(null, parsed); 14 | } 15 | 16 | // returns file content as a string 17 | global.getFileRaw = function(file, cb) { 18 | cb(null, fs.readFileSync(file, 'utf8')); 19 | } 20 | 21 | global.expect = require('chai').expect; 22 | global.FS = fs; 23 | 24 | global.WRITE_GOLDEN = process.env.WRITE_GOLDEN; 25 | global.Converter = require('../../index.js'); 26 | 27 | global.TestSuites = require('./../test-cases.js'); 28 | global.TestCases = TestSuites.TestCases; 29 | global.SyntaxTestCases = TestSuites.SyntaxTestCases; 30 | 31 | -------------------------------------------------------------------------------- /test/test-cases.js: -------------------------------------------------------------------------------- 1 | var TestCases = [] 2 | 3 | TestCases.push({ 4 | in: {format: 'swagger_1', directory: 'petstore', file: 'index.json'}, 5 | out: {format: 'swagger_2', file: 'petstore.json'} 6 | }) 7 | 8 | TestCases.push({ 9 | in: {format: 'api_blueprint', file: 'simplest.md'}, 10 | out: {format: 'swagger_2', file: 'simplest.json'} 11 | }) 12 | 13 | TestCases.push({ 14 | in: {format: 'api_blueprint', file: 'polls_api.md'}, 15 | out: {format: 'swagger_2', file: 'polls.json'}, 16 | }) 17 | 18 | TestCases.push({ 19 | in: {format: 'api_blueprint', file: 'parameters.md'}, 20 | out: {format: 'swagger_2', file: 'parameters.json'}, 21 | }) 22 | 23 | TestCases.push({ 24 | in: {format: 'wadl', file: 'facebook.xml'}, 25 | out: {format: 'swagger_2', file: 'facebook.json'}, 26 | }) 27 | 28 | TestCases.push({ 29 | in: {format: 'wadl', file: 'sample_wadl.wadl'}, 30 | out: {format: 'swagger_2', file: 'sample_wadl.json'}, 31 | }) 32 | 33 | TestCases.push({ 34 | in: {format: 'wadl', file: 'OpenStack_example.wadl'}, 35 | out: {format: 'swagger_2', file: 'OpenStack_example.json'}, 36 | }) 37 | 38 | TestCases.push({ 39 | in: {format: 'wadl', file: 'regex_paths.wadl'}, 40 | out: {format: 'swagger_2', file: 'regex_paths.json'}, 41 | }) 42 | 43 | var IODOCS_FILES = ['usatoday', 'egnyte', 'foursquare', 'klout']; 44 | TestCases = TestCases.concat(IODOCS_FILES.map(function(file) { 45 | return { 46 | in: {format: 'io_docs', file: file + '.json'}, 47 | out: {format: 'swagger_2', file: file + '.json'}, 48 | } 49 | })) 50 | 51 | TestCases.push({ 52 | in: {format: 'google', file: 'youtube.json'}, 53 | out: {format: 'swagger_2', file: 'youtube.json'} 54 | }) 55 | 56 | TestCases.push({ 57 | in: {format: 'raml', directory: 'XKCD', file: 'api.raml'}, 58 | out: {format: 'swagger_2', file: 'XKCD.json'} 59 | }) 60 | 61 | TestCases.push({ 62 | in: {format: 'openapi_3', file: 'deprecated.yml'}, 63 | out: {format: 'swagger_2', file: 'deprecated.yml'}, 64 | skipBrowser: true, 65 | }) 66 | 67 | TestCases.push({ 68 | in: {format: 'swagger_2', file: 'petstore.json'}, 69 | out: {format: 'openapi_3', file: 'petstore2.json'} 70 | }) 71 | 72 | TestCases.push({ 73 | in: {format: 'openapi_3', file: 'petstore.json'}, 74 | out: {format: 'swagger_2', file: 'petstore_from_oas3.json'} 75 | }) 76 | 77 | TestCases.push({ 78 | in: {format: 'openapi_3', file: 'minimal.json'}, 79 | out: {format: 'swagger_2', file: 'minimal.json'} 80 | }) 81 | 82 | TestCases.push({ 83 | in: {format: 'openapi_3', file: 'produces.yml'}, 84 | out: {format: 'swagger_2', file: 'produces.json'} 85 | }) 86 | 87 | TestCases.push({ 88 | in: {format: 'openapi_3', file: 'param_schema_ref.yml'}, 89 | out: {format: 'swagger_2', file: 'param_schema_ref.json'} 90 | }) 91 | 92 | TestCases.push({ 93 | in: {format: 'openapi_3', file: 'servers.yml'}, 94 | out: {format: 'swagger_2', file: 'servers.json'} 95 | }) 96 | 97 | TestCases.push({ 98 | in: {format: 'openapi_3', file: 'slash_ref.yml'}, 99 | out: {format: 'swagger_2', file: 'slash_ref.json'} 100 | }) 101 | 102 | TestCases.push({ 103 | in: {format: 'openapi_3', file: 'has_external_ref.json'}, 104 | out: {format: 'swagger_2', file: 'has_external_ref.json'}, 105 | skipBrowser: true, 106 | }) 107 | 108 | TestCases.push({ 109 | in: {format: 'openapi_3', file: 'yaml_with_ref.yml'}, 110 | out: {format: 'swagger_2', file: 'yaml_with_ref.yml', syntax: 'yaml'}, 111 | skipBrowser: true, 112 | }) 113 | 114 | TestCases.push({ 115 | in: {format: 'openapi_3', file: 'common_params.json'}, 116 | out: {format: 'swagger_2', file: 'common_params.json'}, 117 | skipBrowser: true, 118 | }) 119 | 120 | TestCases.push({ 121 | in: {format: 'openapi_3', file: 'form_param.yml'}, 122 | out: {format: 'swagger_2', file: 'form_param.yml', syntax: 'yaml'}, 123 | skipBrowser: true, 124 | }) 125 | 126 | TestCases.push({ 127 | in: {format: 'openapi_3', file: 'nullable.yml'}, 128 | out: {format: 'swagger_2', file: 'nullable.yml', syntax: 'yaml'}, 129 | skipBrowser: true, 130 | }) 131 | 132 | TestCases.push({ 133 | in: {format: 'openapi_3', file: 'nested_oneof.yml'}, 134 | out: {format: 'swagger_2', file: 'nested_oneof.yml', syntax: 'yaml'}, 135 | skipBrowser: true, 136 | }) 137 | 138 | TestCases.push({ 139 | in: {format: 'openapi_3', file: 'request_response_ref.yml'}, 140 | out: {format: 'swagger_2', file: 'request_response_ref.yml', syntax: 'yaml'}, 141 | skipBrowser: true, 142 | }) 143 | 144 | TestCases.push({ 145 | in: {format: 'openapi_3', file: 'multiple_ref.yml'}, 146 | out: {format: 'swagger_2', file: 'multiple_ref.json', syntax: 'json'}, 147 | skipBrowser: true, 148 | }) 149 | 150 | var openapi3Cases = []; 151 | 152 | TestCases.forEach(function(testCase) { 153 | if (testCase.out.format === 'swagger_2' && testCase.in.format !== 'openapi_3') { 154 | var newCase = JSON.parse(JSON.stringify(testCase)); 155 | newCase.out.format = 'openapi_3'; 156 | openapi3Cases.push(newCase); 157 | } 158 | }) 159 | 160 | TestCases = TestCases.concat(openapi3Cases); 161 | 162 | //------------------ Json & Yaml test cases ------------------- 163 | 164 | var SyntaxTestCases = [] 165 | 166 | SyntaxTestCases.push({ 167 | in: {format: 'swagger_1', directory: 'petstore', file: 'index.json'}, 168 | out: {format: 'swagger_2', file: 'petstore.json', syntax: 'json', order: 'alpha'} 169 | }) 170 | 171 | SyntaxTestCases.push({ 172 | in: {format: 'swagger_1', directory: 'petstore', file: 'index.json'}, 173 | out: {format: 'swagger_2', file: 'petstore.yaml', syntax: 'yaml', order: 'alpha'} 174 | }) 175 | 176 | SyntaxTestCases.push({ 177 | in: {format: 'swagger_1', directory: 'petstore', file: 'index.json'}, 178 | out: {format: 'swagger_2', file: 'petstore-oa.yaml', syntax: 'yaml', order: 'openapi'} 179 | }) 180 | 181 | SyntaxTestCases.push({ 182 | in: {format: 'openapi_3', file: 'param_schema_ref.yml'}, 183 | out: {format: 'swagger_2', file: 'param_schema_unordered_ref.json', order: 'false'} 184 | }) 185 | 186 | //---- exports ---- 187 | 188 | if (typeof module !== 'undefined') { 189 | module.exports = {TestCases: TestCases, SyntaxTestCases: SyntaxTestCases}; 190 | } else { 191 | // TODO I could not test this branch. 192 | // It should probably be updated to look like the one in the module block above 193 | window.TestCases = TestCases; 194 | } 195 | -------------------------------------------------------------------------------- /web/.angular-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "project": { 4 | "name": "ng-universal-demo" 5 | }, 6 | "apps": [ 7 | { 8 | "name": "browser", 9 | "root": "src", 10 | "outDir": "dist/browser", 11 | "assets": [ 12 | "assets", 13 | "favicon.png" 14 | ], 15 | "index": "index.html", 16 | "main": "main.ts", 17 | "polyfills": "polyfills.ts", 18 | "test": "test.ts", 19 | "tsconfig": "tsconfig.app.json", 20 | "testTsconfig": "tsconfig.spec.json", 21 | "prefix": "app", 22 | "styles": [ 23 | "app/styles/styles.scss", 24 | "../node_modules/font-awesome/css/font-awesome.min.css" 25 | ], 26 | "scripts": [ 27 | "../node_modules/jquery/dist/jquery.min.js", 28 | "../node_modules/bootstrap/dist/js/bootstrap.min.js", 29 | "../../dist/api-spec-converter.js" 30 | ], 31 | "environmentSource": "environments/environment.ts", 32 | "environments": { 33 | "dev": "environments/environment.ts", 34 | "prod": "environments/environment.prod.ts" 35 | } 36 | }, 37 | { 38 | "name": "server", 39 | "platform": "server", 40 | "root": "src", 41 | "outDir": "dist/server", 42 | "assets": [ 43 | "assets", 44 | "favicon.png" 45 | ], 46 | "index": "index.html", 47 | "main": "main.server.ts", 48 | "test": "test.ts", 49 | "tsconfig": "tsconfig.server.json", 50 | "testTsconfig": "tsconfig.spec.json", 51 | "prefix": "app", 52 | "styles": [ 53 | "app/styles/styles.scss", 54 | "../node_modules/font-awesome/css/font-awesome.min.css" 55 | ], 56 | "scripts": [ 57 | "../node_modules/jquery/dist/jquery.min.js", 58 | "../node_modules/bootstrap/dist/js/bootstrap.min.js", 59 | "../../dist/api-spec-converter.js" 60 | ], 61 | "environmentSource": "environments/environment.ts", 62 | "environments": { 63 | "dev": "environments/environment.ts", 64 | "prod": "environments/environment.prod.ts" 65 | } 66 | } 67 | ], 68 | "e2e": { 69 | "protractor": { 70 | "config": "./protractor.conf.js" 71 | } 72 | }, 73 | "lint": [ 74 | { 75 | "project": "src/tsconfig.app.json", 76 | "exclude": "**/node_modules/**" 77 | }, 78 | { 79 | "project": "src/tsconfig.spec.json", 80 | "exclude": "**/node_modules/**" 81 | }, 82 | { 83 | "project": "e2e/tsconfig.e2e.json", 84 | "exclude": "**/node_modules/**" 85 | } 86 | ], 87 | "test": { 88 | "karma": { 89 | "config": "./karma.conf.js" 90 | } 91 | }, 92 | "defaults": { 93 | "styleExt": "css", 94 | "component": { 95 | "spec": false, 96 | "inlineStyle": true, 97 | "inlineTemplate": true 98 | }, 99 | "directive": { 100 | "spec": false 101 | }, 102 | "class": { 103 | "spec": false 104 | }, 105 | "guard": { 106 | "spec": false 107 | }, 108 | "module": { 109 | "spec": false 110 | }, 111 | "pipe": { 112 | "spec": false 113 | }, 114 | "service": { 115 | "spec": false 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /web/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | 3 | .idea 4 | .DS_Store 5 | morgan.log 6 | 7 | # Built # 8 | /__build__/ 9 | /__server_build__/ 10 | /node_modules/ 11 | /typings/ 12 | /tsd_typings/ 13 | /dist/ 14 | /dist-server/ 15 | /compiled/ 16 | 17 | # Node # 18 | npm-debug.log 19 | /npm-debug.log.* 20 | 21 | # Webpack # 22 | webpack.records.json 23 | 24 | # Angular # 25 | *.ngfactory.ts 26 | *.css.shim.ts 27 | *.ngsummary.json 28 | *.metadata.json 29 | *.shim.ngstyle.ts 30 | -------------------------------------------------------------------------------- /web/README.md: -------------------------------------------------------------------------------- 1 | # Angluar 4.0 Template Project 2 | I use this template as a starter for any new Angular projects. 3 | 4 | Check out [the demo](https://bobby-brennan.github.io/angular4-template) 5 | 6 | #### Features 7 | * Angular Universal (prerendering) 8 | * [Pug](https://pugjs.org) templates instead of HTML 9 | * Bootstrap Sass 10 | * Font Awesome 11 | * Angular HTML5 Router 12 | * Standard navbar/body layout 13 | 14 | ## Running the Demo 15 | 16 | #### Install 17 | 18 | ``` 19 | npm install 20 | ``` 21 | 22 | #### Run (development mode) 23 | Start the server on port 3000: 24 | 25 | ``` 26 | npm run start 27 | ``` 28 | 29 | 30 | #### Build (production) 31 | Build everything and put it in the `dist/` folder: 32 | 33 | ``` 34 | npm run build 35 | ``` 36 | 37 | Or build for GitHub pages by copying `dist/browser` to `docs/`. 38 | Be sure to change the settings in your repo to point GitHub pages to 39 | the `docs/` folder on the `master` branch. 40 | 41 | ## Customizing 42 | 43 | ### Base href 44 | The app uses the base href `/` for development builds, and `/angular4-template` 45 | for production builds (to accomodate GitHub pages, which uses the repository 46 | name in the URL's path). You will probably want to change the base href in 47 | `./src/environments/environment.prod.ts`. 48 | 49 | ### Prerendering 50 | Prerendering is a performance optimization - your page's HTML is generated 51 | at build time, so the user sees a near-instant load of the page, while Angular 52 | loads in the background. 53 | 54 | In this build, only the homepage is prerendered - you can add other routes 55 | by editing `./static.paths.ts`. 56 | 57 | ## New Components 58 | A helper script for creating new components is in `./scripts/new-component.js`. 59 | 60 | ``` 61 | node ./scripts/new-component.js --name "Widget Viewer" 62 | ``` 63 | -------------------------------------------------------------------------------- /web/docs/3rdpartylicenses.txt: -------------------------------------------------------------------------------- 1 | core-js@2.5.1 2 | MIT 3 | Copyright (c) 2014-2017 Denis Pushkarev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | webpack@3.6.0 24 | MIT 25 | Copyright JS Foundation and other contributors 26 | 27 | Permission is hereby granted, free of charge, to any person obtaining 28 | a copy of this software and associated documentation files (the 29 | 'Software'), to deal in the Software without restriction, including 30 | without limitation the rights to use, copy, modify, merge, publish, 31 | distribute, sublicense, and/or sell copies of the Software, and to 32 | permit persons to whom the Software is furnished to do so, subject to 33 | the following conditions: 34 | 35 | The above copyright notice and this permission notice shall be 36 | included in all copies or substantial portions of the Software. 37 | 38 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 39 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 40 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 41 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 42 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 43 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 44 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 45 | 46 | zone.js@0.8.18 47 | MIT 48 | The MIT License 49 | 50 | Copyright (c) 2016 Google, Inc. 51 | 52 | Permission is hereby granted, free of charge, to any person obtaining a copy 53 | of this software and associated documentation files (the "Software"), to deal 54 | in the Software without restriction, including without limitation the rights 55 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 56 | copies of the Software, and to permit persons to whom the Software is 57 | furnished to do so, subject to the following conditions: 58 | 59 | The above copyright notice and this permission notice shall be included in 60 | all copies or substantial portions of the Software. 61 | 62 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 63 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 64 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 65 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 66 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 67 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 68 | THE SOFTWARE. 69 | 70 | @angular/core@4.4.5 71 | MIT 72 | MIT 73 | 74 | @angular/router@4.4.5 75 | MIT 76 | MIT 77 | 78 | @angular/http@4.4.5 79 | MIT 80 | MIT 81 | 82 | @angular/forms@4.4.5 83 | MIT 84 | MIT 85 | 86 | @angular/platform-browser@4.4.5 87 | MIT 88 | MIT 89 | 90 | @angular/common@4.4.5 91 | MIT 92 | MIT -------------------------------------------------------------------------------- /web/docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucyBot-Inc/api-spec-converter/f51ac3660533835b2e6e424ec4356375112433b2/web/docs/favicon.ico -------------------------------------------------------------------------------- /web/docs/fontawesome-webfont.674f50d287a8c48dc19b.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucyBot-Inc/api-spec-converter/f51ac3660533835b2e6e424ec4356375112433b2/web/docs/fontawesome-webfont.674f50d287a8c48dc19b.eot -------------------------------------------------------------------------------- /web/docs/fontawesome-webfont.af7ae505a9eed503f8b8.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucyBot-Inc/api-spec-converter/f51ac3660533835b2e6e424ec4356375112433b2/web/docs/fontawesome-webfont.af7ae505a9eed503f8b8.woff2 -------------------------------------------------------------------------------- /web/docs/fontawesome-webfont.b06871f281fee6b241d6.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucyBot-Inc/api-spec-converter/f51ac3660533835b2e6e424ec4356375112433b2/web/docs/fontawesome-webfont.b06871f281fee6b241d6.ttf -------------------------------------------------------------------------------- /web/docs/fontawesome-webfont.fee66e712a8a08eef580.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucyBot-Inc/api-spec-converter/f51ac3660533835b2e6e424ec4356375112433b2/web/docs/fontawesome-webfont.fee66e712a8a08eef580.woff -------------------------------------------------------------------------------- /web/docs/glyphicons-halflings-regular.448c34a56d699c29117a.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucyBot-Inc/api-spec-converter/f51ac3660533835b2e6e424ec4356375112433b2/web/docs/glyphicons-halflings-regular.448c34a56d699c29117a.woff2 -------------------------------------------------------------------------------- /web/docs/glyphicons-halflings-regular.e18bbf611f2a2e43afc0.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucyBot-Inc/api-spec-converter/f51ac3660533835b2e6e424ec4356375112433b2/web/docs/glyphicons-halflings-regular.e18bbf611f2a2e43afc0.ttf -------------------------------------------------------------------------------- /web/docs/glyphicons-halflings-regular.f4769f9bdb7466be6508.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucyBot-Inc/api-spec-converter/f51ac3660533835b2e6e424ec4356375112433b2/web/docs/glyphicons-halflings-regular.f4769f9bdb7466be6508.eot -------------------------------------------------------------------------------- /web/docs/glyphicons-halflings-regular.fa2772327f55d8198301.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucyBot-Inc/api-spec-converter/f51ac3660533835b2e6e424ec4356375112433b2/web/docs/glyphicons-halflings-regular.fa2772327f55d8198301.woff -------------------------------------------------------------------------------- /web/docs/index.html: -------------------------------------------------------------------------------- 1 | Angular 4 Template 2 | 3 |
4 | 5 |

Home

6 |

Angluar 4.0 Template Project

7 |

I use this template as a starter for any new Angular projects.

8 |

Check out the demo

9 |

Features

10 |
    11 |
  • Angular Universal (prerendering)
  • 12 |
  • Pug templates instead of HTML
  • 13 |
  • Bootstrap Sass
  • 14 |
  • Font Awesome
  • 15 |
  • Angular HTML5 Router
  • 16 |
  • Standard navbar/body layout
  • 17 |
18 |

Running the Demo

19 |

Install

20 |
npm install
21 | 

Run (development mode)

22 |

Start the server on port 3000:

23 |
npm run start
24 | 

Build (production)

25 |

Build everything and put it in the dist/ folder:

26 |
npm run build
27 | 

Or build for GitHub pages by copying dist/browser to docs/. 28 | Be sure to change the settings in your repo to point GitHub pages to 29 | the docs/ folder on the master branch.

30 |

Customizing

31 |

Base href

32 |

The app uses the base href / for development builds, and /angular4-template 33 | for production builds (to accomodate GitHub pages, which uses the repository 34 | name in the URL's path). You will probably want to change the base href in 35 | ./src/environments/environment.prod.ts.

36 |

Prerendering

37 |

Prerendering is a performance optimization - your page's HTML is generated 38 | at build time, so the user sees a near-instant load of the page, while Angular 39 | loads in the background.

40 |

In this build, only the homepage is prerendered - you can add other routes 41 | by editing ./static.paths.ts.

42 |

New Components

43 |

A helper script for creating new components is in ./scripts/new-component.js.

44 |
node ./scripts/new-component.js --name "Widget Viewer"
45 | 
46 |
47 |
48 |
-------------------------------------------------------------------------------- /web/docs/inline.4f2476beaacd439998a5.bundle.js: -------------------------------------------------------------------------------- 1 | !function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,c,u){for(var a,i,f,l=0,s=[];l val !== '') 39 | .forEach(function (dir) { 40 | if (!existsSync(dir)) { 41 | mkdirSync(dir); 42 | } 43 | chdir(dir); 44 | }); 45 | 46 | // Writes rendered HTML to index.html, replacing the file if it already exists. 47 | prom = prom.then(_ => renderModuleFactory(AppServerModuleNgFactory, { 48 | document: index, 49 | url: route, 50 | extraProviders: [ 51 | provideModuleMap(LAZY_MODULE_MAP) 52 | ] 53 | })).then(html => writeFileSync(join(BROWSER_FOLDER, route, 'index.html'), html)); 54 | }); 55 | -------------------------------------------------------------------------------- /web/scripts/compare-versions.js: -------------------------------------------------------------------------------- 1 | let fs = require('fs'); 2 | let path = require('path'); 3 | let args = require('yargs').argv; 4 | 5 | function addDirToVersions(dir, versions) { 6 | fs.readdirSync(dir).forEach(d => { 7 | if (d.indexOf('.') === 0) { 8 | return; 9 | } 10 | if (d.indexOf('@') === 0) { 11 | addDirToVersions(dir + '/' + d, versions); 12 | } else { 13 | let pkg = require(dir + '/' + d + '/package.json'); 14 | versions[d] = pkg.version; 15 | } 16 | }) 17 | } 18 | 19 | let aVersions = {}; 20 | addDirToVersions(path.resolve(args.a + '/node_modules'), aVersions); 21 | let bVersions = {}; 22 | addDirToVersions(path.resolve(args.b + '/node_modules'), bVersions); 23 | 24 | let keys = Object.keys(aVersions); 25 | for (let key in bVersions) { 26 | if (keys.indexOf(key) === -1) keys.push(key); 27 | } 28 | 29 | keys.forEach(key => { 30 | let v1 = aVersions[key]; 31 | let v2 = bVersions[key]; 32 | if (v1 !== v2) { 33 | console.log(key + '\t' + aVersions[key] + '\t' + bVersions[key]); 34 | } 35 | }) 36 | -------------------------------------------------------------------------------- /web/scripts/new-component.js: -------------------------------------------------------------------------------- 1 | const args = require('yargs').argv; 2 | const fs = require('fs'); 3 | 4 | let componentCode = function(name, filename) { 5 | return ` 6 | import {Component} from '@angular/core'; 7 | 8 | @Component({ 9 | selector: '${filename}', 10 | templateUrl: './${filename}.pug', 11 | }) 12 | export class ${name}Component { 13 | constructor() {} 14 | } 15 | `.trim() 16 | } 17 | 18 | let viewCode = function(name) { 19 | return ` 20 | h1 ${name} 21 | `.trim(); 22 | } 23 | 24 | const APP_DIR = __dirname + '/../src/app/'; 25 | 26 | const filename = args.name.toLowerCase().replace(/\s/g, '-'); 27 | const componentName = args.name.replace(/\s/g, ''); 28 | const componentDir = APP_DIR + filename + '/'; 29 | const componentFile = componentDir + filename + '.component.ts'; 30 | const viewFile = componentDir + filename + '.pug'; 31 | const appFile = APP_DIR + 'app.module.ts'; 32 | 33 | let component = componentCode(componentName, filename); 34 | let view = viewCode(args.name); 35 | 36 | fs.mkdirSync(componentDir); 37 | fs.writeFileSync(viewFile, view); 38 | fs.writeFileSync(componentFile, component); 39 | 40 | let app = fs.readFileSync(appFile, 'utf8'); 41 | let lines = app.split('\n').reverse(); 42 | 43 | let insertImportAt = lines.findIndex(l => l.match(/^import .* from '\.\/.*.component'/)); 44 | lines.splice(insertImportAt, 0, `import {${componentName}Component} from './${filename}/${filename}.component'`); 45 | 46 | let insertDeclarationAt = lines.findIndex(l => l.match(/^\s+\w+Component,/)); 47 | lines.splice(insertDeclarationAt, 0, ` ${componentName}Component,`) 48 | 49 | lines.reverse(); 50 | fs.writeFileSync(appFile, lines.join('\n')); 51 | -------------------------------------------------------------------------------- /web/server.ts: -------------------------------------------------------------------------------- 1 | import 'zone.js/dist/zone-node'; 2 | import 'reflect-metadata'; 3 | import { renderModuleFactory } from '@angular/platform-server'; 4 | import { enableProdMode } from '@angular/core'; 5 | 6 | import * as express from 'express'; 7 | import { join } from 'path'; 8 | import { readFileSync } from 'fs'; 9 | 10 | // Faster server renders w/ Prod mode (dev mode never needed) 11 | enableProdMode(); 12 | 13 | // Express server 14 | const app = express(); 15 | 16 | const PORT = process.env.PORT || 4000; 17 | const DIST_FOLDER = join(process.cwd(), 'dist'); 18 | 19 | // Our index.html we'll use as our template 20 | const template = readFileSync(join(DIST_FOLDER, 'browser', 'index.html')).toString(); 21 | 22 | // * NOTE :: leave this as require() since this file is built Dynamically from webpack 23 | const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main.bundle'); 24 | 25 | // Express Engine 26 | import { ngExpressEngine } from '@nguniversal/express-engine'; 27 | // Import module map for lazy loading 28 | import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader'; 29 | 30 | // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine) 31 | app.engine('html', ngExpressEngine({ 32 | bootstrap: AppServerModuleNgFactory, 33 | providers: [ 34 | provideModuleMap(LAZY_MODULE_MAP) 35 | ] 36 | })); 37 | 38 | app.set('view engine', 'html'); 39 | app.set('views', join(DIST_FOLDER, 'browser')); 40 | 41 | /* - Example Express Rest API endpoints - 42 | app.get('/api/**', (req, res) => { }); 43 | */ 44 | 45 | // Server static files from /browser 46 | app.get('*.*', express.static(join(DIST_FOLDER, 'browser'), { 47 | maxAge: '1y' 48 | })); 49 | 50 | // ALl regular routes use the Universal engine 51 | app.get('*', (req, res) => { 52 | res.render('index', { req }); 53 | }); 54 | 55 | // Start up the Node server 56 | app.listen(PORT, () => { 57 | console.log(`Node Express server listening on http://localhost:${PORT}`); 58 | }); 59 | -------------------------------------------------------------------------------- /web/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | template: ` 6 |
7 | 8 |
9 | `, 10 | }) 11 | export class AppComponent { 12 | constructor() { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /web/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | import { RouterModule } from '@angular/router'; 4 | import { FormsModule } from '@angular/forms'; 5 | import { HttpModule } from '@angular/http'; 6 | import {APP_BASE_HREF} from '@angular/common'; 7 | 8 | import { AppComponent } from './app.component'; 9 | import { HomeComponent } from './home/home.component'; 10 | import {ReadmeComponent} from './readme/readme.component' 11 | import {SpecConverterComponent} from './spec-converter/spec-converter.component' 12 | 13 | import {PlatformService} from './services/platform.service'; 14 | 15 | import { environment } from '../environments/environment'; 16 | 17 | @NgModule({ 18 | imports: [ 19 | BrowserModule.withServerTransition({appId: 'my-app'}), 20 | HttpModule, 21 | FormsModule, 22 | ], 23 | providers: [ 24 | {provide: APP_BASE_HREF, useValue: environment.baseHref || '/'}, 25 | PlatformService, 26 | ], 27 | declarations: [ 28 | AppComponent, 29 | HomeComponent, 30 | ReadmeComponent, 31 | SpecConverterComponent, 32 | ], 33 | bootstrap: [ AppComponent ], 34 | }) 35 | export class AppModule { } 36 | -------------------------------------------------------------------------------- /web/src/app/app.server.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {ServerModule} from '@angular/platform-server'; 3 | import {ModuleMapLoaderModule} from '@nguniversal/module-map-ngfactory-loader'; 4 | 5 | import {AppModule} from './app.module'; 6 | import {AppComponent} from './app.component'; 7 | 8 | @NgModule({ 9 | imports: [ 10 | // The AppServerModule should import your AppModule followed 11 | // by the ServerModule from @angular/platform-server. 12 | AppModule, 13 | ServerModule, 14 | ModuleMapLoaderModule, 15 | ], 16 | // Since the bootstrapped component is not inherited from your 17 | // imported AppModule, it needs to be repeated here. 18 | bootstrap: [AppComponent], 19 | }) 20 | export class AppServerModule {} 21 | -------------------------------------------------------------------------------- /web/src/app/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | import {Router} from '@angular/router'; 3 | 4 | @Component({ 5 | selector: 'home', 6 | templateUrl: './home.pug', 7 | styles: [` 8 | h1 { 9 | margin-bottom: 50px; 10 | } 11 | .social-buttons { 12 | margin-bottom: 20px; 13 | } 14 | .social-buttons .fa { 15 | font-size: 18px; 16 | } 17 | spec-converter { 18 | display: block; 19 | margin-top: 50px; 20 | } 21 | `], 22 | }) 23 | export class HomeComponent { 24 | githubLink = 'https://github.com/LucyBot-Inc/api-spec-converter'; 25 | 26 | constructor() { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /web/src/app/home/home.pug: -------------------------------------------------------------------------------- 1 | .row 2 | .col-xs-12.col-md-10.col-md-offset-1 3 | h1 4 | span API Spec Converter 5 | .btn-toolbar.social-buttons.pull-right 6 | a.btn.btn-default([href]="githubLink") 7 | i.fa.fa-left.fa-github 8 | span View on GitHub 9 | a.btn.btn-default( 10 | href="https://twitter.com/intent/tweet?text=Convert+between+API+description+formats+such+as+Swagger+and+RAML:&url=http%3A%2F%2Flucybot-inc.github.io%2Fapi-spec-converter") 11 | i.fa.fa-left.fa-twitter 12 | span Tweet 13 | p 14 | |The goal of this project is to allow REST API developers to convert between different 15 | |API definition formats. 16 | |This prevents lock-in, and allows developers to take advantage 17 | |of tools that only support particular formats. 18 | p. 19 | Currently, we only support converting from various formats (e.g. RAML and WADL) to Open API 2.0 (fka Swagger). 20 | Open API 3.0 and API Blueprint are not supported in this web app, but are supported using the 21 | command line tool. 22 | p. 23 | Our plan is to eventually support conversion between any two formats. If you'd like to contribute, you can 24 | check out the open source library on GitHub. 25 | spec-converter 26 | -------------------------------------------------------------------------------- /web/src/app/readme/readme.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'readme', 5 | templateUrl: '../../../README.md', 6 | }) 7 | export class ReadmeComponent { 8 | constructor() {} 9 | } 10 | -------------------------------------------------------------------------------- /web/src/app/readme/readme.pug: -------------------------------------------------------------------------------- 1 | h1 Readme -------------------------------------------------------------------------------- /web/src/app/services/platform.service.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Injectable, PLATFORM_ID } from '@angular/core' 2 | import { isPlatformBrowser, isPlatformServer } from '@angular/common' 3 | 4 | @Injectable() 5 | export class PlatformService { 6 | constructor(@Inject(PLATFORM_ID) private platformId: any) { } 7 | 8 | public isBrowser(): boolean { 9 | return isPlatformBrowser(this.platformId) 10 | } 11 | 12 | public isServer(): boolean { 13 | return isPlatformServer(this.platformId) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /web/src/app/spec-converter/spec-converter.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | 3 | import {PlatformService} from '../services/platform.service'; 4 | 5 | declare let APISpecConverter:any; 6 | 7 | import {saveAs} from 'file-saver'; 8 | 9 | @Component({ 10 | selector: 'spec-converter', 11 | templateUrl: './spec-converter.pug', 12 | styles: [` 13 | button[type="submit"] { 14 | margin-top: 12px; 15 | float: right; 16 | } 17 | 18 | .output-spec { 19 | margin-top: 50px; 20 | } 21 | `] 22 | }) 23 | export class SpecConverterComponent { 24 | spec:any; 25 | error:string; 26 | running:boolean; 27 | 28 | convertFrom:string; 29 | convertTo:string; 30 | convertSource:string; 31 | 32 | formats:string[]=[]; 33 | skipFormats = ['api_blueprint']; 34 | destinationFormats = ['swagger_2', 'openapi_3']; 35 | formatLabels = { 36 | swagger_1: 'Open API 1.x (Swagger)', 37 | swagger_2: 'Open API 2.0 (Swagger)', 38 | openapi_3: 'Open API 3.0', 39 | io_docs: 'I/O Docs', 40 | api_blueprint: 'API Blueprint', 41 | google: 'Google Discovery', 42 | raml: 'RAML', 43 | wadl: 'WADL', 44 | }; 45 | examples = [ 46 | {from: 'swagger_1', source: 'https://raw.githubusercontent.com/LucyBot-Inc/api-spec-converter/master/test/input/swagger_1/petstore/index.json'}, 47 | {from: 'swagger_2', to: 'openapi_3', source: 'https://api.apis.guru/v2/specs/bufferapp.com/1/swagger.json'}, 48 | {from: 'wadl', source: 'https://api.apigee.com/v1/consoles/facebook/apidescription?format=wadl'}, 49 | {from: 'raml', source: 'https://raw.githubusercontent.com/raml-apis/XKCD/master/api.raml'}, 50 | {from: 'google', source: 'https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest'}, 51 | //{from: 'api_blueprint', source: 'https://raw.githubusercontent.com/apiaryio/api-blueprint/master/examples/Polls%20API.md'}, 52 | {from: 'io_docs', source: 'https://raw.githubusercontent.com/lucybot/api-spec-converter/master/test/input/io_docs/foursquare.json'}, 53 | ]; 54 | 55 | constructor(public platform:PlatformService) { 56 | this.setExample(this.examples[0]); 57 | if (this.platform.isBrowser()) { 58 | this.formats = Object.keys(APISpecConverter.Formats); 59 | } 60 | } 61 | 62 | stringify(obj) { 63 | return JSON.stringify(obj, null, 2); 64 | } 65 | 66 | setExample(example) { 67 | this.convertFrom = example.from; 68 | this.convertTo = example.to || 'swagger_2'; 69 | this.convertSource = example.source; 70 | } 71 | 72 | convert() { 73 | this.error = this.spec = null; 74 | this.running = true; 75 | APISpecConverter.convert({from: this.convertFrom, to: this.convertTo, source: this.convertSource}) 76 | .then( 77 | spec => this.spec = spec.spec, 78 | err => { 79 | this.error = err; 80 | console.log(err); 81 | } 82 | ) 83 | .then(_ => this.running = false); 84 | } 85 | 86 | download() { 87 | var blob = new Blob([this.stringify(this.spec)], {type: 'application/json;charset=utf-8'}); 88 | saveAs(blob, 'swagger.json'); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /web/src/app/spec-converter/spec-converter.pug: -------------------------------------------------------------------------------- 1 | form((submit)="convert()") 2 | .form-group 3 | label Specification URL 4 | .input-group 5 | input.form-control(type="text" placeholder="Source URL" [(ngModel)]="convertSource" name="source") 6 | .input-group-btn 7 | a.btn.btn-default.dropdown-toggle(data-toggle="dropdown" type="button" aria-haspopup="true" aria-expanded="false") 8 | span Examples 9 | i.fa.fa-right.fa-caret-down 10 | ul.dropdown-menu 11 | li(*ngFor="let example of examples") 12 | a((click)="setExample(example)") 13 | span {{ formatLabels[example.from] || example.from }} 14 | .row 15 | .col-xs-12.col-sm-4 16 | .form-group 17 | label Source Format 18 | .dropdown 19 | button.btn.btn-default.dropdown-toggle(data-toggle="dropdown" type="button" aria-haspopup="true" aria-expanded="false") 20 | span {{ formatLabels[convertFrom] || convertFrom }} 21 | i.fa.fa-right.fa-caret-down 22 | ul.dropdown-menu 23 | li(*ngFor="let format of formats" [hidden]="skipFormats.indexOf(format) !== -1") 24 | a((click)="convertFrom = format") {{formatLabels[format] || format}} 25 | .col-xs-12.col-sm-4 26 | .form-group 27 | label Destination Format 28 | .dropdown 29 | button.btn.btn-default.dropdown-toggle(data-toggle="dropdown" type="button" aria-haspopup="true" aria-expanded="false") 30 | span {{ formatLabels[convertTo] || convertTo }} 31 | i.fa.fa-right.fa-caret-down 32 | ul.dropdown-menu 33 | li(*ngFor="let format of destinationFormats" [hidden]="skipFormats.indexOf(format) !== -1 || format === convertFrom") 34 | a((click)="convertTo = format") {{formatLabels[format] || format}} 35 | .col-xs-12.col-sm-4 36 | .form-group 37 | button.btn.btn-lg.btn-success(type="submit" [disabled]="running || !platform.isBrowser()") 38 | span(*ngIf="!running && platform.isBrowser()") 39 | span.fa.fa-exchange 40 | span  Convert! 41 | span.fa.fa-spin.fa-refresh(*ngIf="running || !platform.isBrowser()") 42 | .alert.alert-danger(*ngIf="error") 43 | p {{ error }} 44 | p 45 | a(href="https://github.com/lucybot/api-spec-converter/issues/new" target="_blank") Open an issue on GitHub 46 | .output-spec(*ngIf="spec") 47 | .row 48 | .col-xs-9 49 | p 50 | span Converted to {{ formatLabels[convertTo] || convertTo }}. 51 | .col-xs-3.text-right 52 | p 53 | a((click)="download()") 54 | span.fa.fa-left.fa-download 55 | span Download 56 | pre {{ stringify(spec) }} 57 | -------------------------------------------------------------------------------- /web/src/app/styles/app.scss: -------------------------------------------------------------------------------- 1 | [hidden] { 2 | display: none !important; 3 | } 4 | 5 | a { 6 | cursor: pointer; 7 | } 8 | 9 | .navbar { 10 | border-radius: 0px; 11 | } 12 | 13 | body { 14 | position: relative; 15 | } 16 | 17 | app > .container { 18 | padding-bottom: 72px; 19 | } 20 | 21 | footer { 22 | position: absolute; 23 | bottom: 0; 24 | left: 0; 25 | right: 0; 26 | 27 | background-color: #fff; 28 | padding-top: 20px; 29 | padding-bottom: 20px; 30 | } 31 | 32 | footer, footer a { 33 | color: #3E3F3A; 34 | } 35 | 36 | .fa-left { 37 | margin-right: 8px; 38 | } 39 | .fa-right { 40 | margin-left: 8px; 41 | } 42 | -------------------------------------------------------------------------------- /web/src/app/styles/styles.scss: -------------------------------------------------------------------------------- 1 | @import 'variables'; 2 | 3 | $icon-font-path: '~bootstrap-sass/assets/fonts/bootstrap/'; 4 | @import '~bootstrap-sass/assets/stylesheets/bootstrap'; 5 | 6 | @import './app.scss'; 7 | 8 | -------------------------------------------------------------------------------- /web/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucyBot-Inc/api-spec-converter/f51ac3660533835b2e6e424ec4356375112433b2/web/src/assets/.gitkeep -------------------------------------------------------------------------------- /web/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | baseHref: '/api-spec-converter', 4 | }; 5 | -------------------------------------------------------------------------------- /web/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false, 8 | baseHref: '/', 9 | }; 10 | -------------------------------------------------------------------------------- /web/src/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucyBot-Inc/api-spec-converter/f51ac3660533835b2e6e424ec4356375112433b2/web/src/favicon.png -------------------------------------------------------------------------------- /web/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | API Spec Converter 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /web/src/main.server.ts: -------------------------------------------------------------------------------- 1 | export { AppServerModule } from './app/app.server.module'; 2 | -------------------------------------------------------------------------------- /web/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | document.addEventListener('DOMContentLoaded', () => { 12 | platformBrowserDynamic().bootstrapModule(AppModule); 13 | }); 14 | -------------------------------------------------------------------------------- /web/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/ 22 | // import 'core-js/es6/symbol'; 23 | // import 'core-js/es6/object'; 24 | // import 'core-js/es6/function'; 25 | // import 'core-js/es6/parse-int'; 26 | // import 'core-js/es6/parse-float'; 27 | // import 'core-js/es6/number'; 28 | // import 'core-js/es6/math'; 29 | // import 'core-js/es6/string'; 30 | // import 'core-js/es6/date'; 31 | // import 'core-js/es6/array'; 32 | // import 'core-js/es6/regexp'; 33 | // import 'core-js/es6/map'; 34 | // import 'core-js/es6/weak-map'; 35 | // import 'core-js/es6/set'; 36 | 37 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 38 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 39 | 40 | /** Evergreen browsers require these. **/ 41 | import 'core-js/es6/reflect'; 42 | import 'core-js/es7/reflect'; 43 | 44 | 45 | /** 46 | * Required to support Web Animations `@angular/animation`. 47 | * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation 48 | **/ 49 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 50 | 51 | 52 | import 'babel-polyfill'; 53 | 54 | /*************************************************************************************************** 55 | * Zone JS is required by Angular itself. 56 | */ 57 | import 'zone.js/dist/zone'; // Included with Angular CLI. 58 | 59 | 60 | 61 | /*************************************************************************************************** 62 | * APPLICATION IMPORTS 63 | */ 64 | 65 | /** 66 | * Date, currency, decimal and percent pipes. 67 | * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10 68 | */ 69 | // import 'intl'; // Run `npm install --save intl`. 70 | /** 71 | * Need to import at least one locale-data with intl. 72 | */ 73 | // import 'intl/locale-data/jsonp/en'; 74 | -------------------------------------------------------------------------------- /web/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "baseUrl": "./", 6 | "module": "es2015", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /web/src/tsconfig.server.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "baseUrl": "./", 6 | // Set the module format to "commonjs": 7 | "module": "commonjs", 8 | "types": [] 9 | }, 10 | "exclude": [ 11 | "test.ts", 12 | "**/*.spec.ts" 13 | ], 14 | // Add "angularCompilerOptions" with the AppServerModule you wrote 15 | // set as the "entryModule". 16 | "angularCompilerOptions": { 17 | "entryModule": "app/app.server.module#AppServerModule" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /web/static.paths.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '/', 3 | ]; 4 | -------------------------------------------------------------------------------- /web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "target": "es5", 11 | "typeRoots": [ 12 | "node_modules/@types" 13 | ], 14 | "lib": [ 15 | "es2017", 16 | "dom" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /web/webpack.cli-additions.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const commonCliConfig = 'node_modules/@angular/cli/models/webpack-configs/common.js'; 3 | const addition_rules = ` 4 | { test: /\.(pug|jade)$/, loader: 'apply-loader' }, 5 | { test: /\.(pug|jade)$/, 6 | loader: 'pug-loader', 7 | query: { doctype: 'html', plugins: [require('pug-plugin-ng')] }, 8 | }, 9 | { 10 | test: /\.js$/, 11 | use: [{ 12 | loader: 'babel-loader', 13 | options: { 14 | presets: ['env'], 15 | } 16 | }], 17 | }, 18 | { test: /\.md$/, use: [{ loader: 'raw-loader' }, { loader: 'markdown-loader', }] } 19 | ,`; // make sure to have this last comma 20 | 21 | fs.readFile(commonCliConfig, (err, data) => { 22 | 23 | if (err) { throw err; } 24 | 25 | const configText = data.toString(); 26 | // make sure we don't include it (if we've already done this) 27 | if (configText.indexOf(addition_rules) > -1) { return; } 28 | 29 | console.log('-- Inserting additional webpack rules to node_modules CLI -- '); 30 | 31 | const position = configText.indexOf('rules: [') + 8; 32 | const output = [configText.slice(0, position), addition_rules, configText.slice(position)].join(''); 33 | fs.writeFileSync(commonCliConfig, output); 34 | }); 35 | 36 | -------------------------------------------------------------------------------- /web/webpack.server.config.js: -------------------------------------------------------------------------------- 1 | // Work around for https://github.com/angular/angular-cli/issues/7200 2 | 3 | const path = require('path'); 4 | const webpack = require('webpack'); 5 | 6 | module.exports = { 7 | entry: { 8 | // This is our Express server for Dynamic universal 9 | server: './server.ts', 10 | // This is an example of Static prerendering (generative) 11 | prerender: './prerender.ts' 12 | }, 13 | target: 'node', 14 | resolve: { extensions: ['.ts', '.js'] }, 15 | // Make sure we include all node_modules etc 16 | externals: [/(node_modules|main\..*\.js)/,], 17 | output: { 18 | // Puts the output at the root of the dist folder 19 | path: path.join(__dirname, 'dist'), 20 | filename: '[name].js' 21 | }, 22 | module: { 23 | rules: [ 24 | { test: /\.ts$/, loader: 'ts-loader' } 25 | ] 26 | }, 27 | plugins: [ 28 | new webpack.ContextReplacementPlugin( 29 | // fixes WARNING Critical dependency: the request of a dependency is an expression 30 | /(.+)?angular(\\|\/)core(.+)?/, 31 | path.join(__dirname, 'src'), // location of your src 32 | {} // a map of your routes 33 | ), 34 | new webpack.ContextReplacementPlugin( 35 | // fixes WARNING Critical dependency: the request of a dependency is an expression 36 | /(.+)?express(\\|\/)(.+)?/, 37 | path.join(__dirname, 'src'), 38 | {} 39 | ) 40 | ] 41 | } 42 | --------------------------------------------------------------------------------