diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index b5ce424..b6e49a6 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [10.x, 12.x] + node-version: [10.x, 12.x, 14.x] steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} diff --git a/.gitignore b/.gitignore index f71ae25..b622746 100644 --- a/.gitignore +++ b/.gitignore @@ -39,4 +39,6 @@ node_modules/* .env.test # parcel-bundler cache (https://parceljs.org/) -.cache \ No newline at end of file +.cache + +.idea diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..e7ddcac --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "cSpell.words": [ + "execa" + ] +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index d38a628..cb77fa6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,40 @@ +## [1.8.0](https://github.com/joolfe/postman-to-openapi/compare/1.7.1...1.8.0) (2021-04-30) + + +### Features + +* addd testa dn support for node 14 Close [#104](https://github.com/joolfe/postman-to-openapi/issues/104) ([4fe0284](https://github.com/joolfe/postman-to-openapi/commit/4fe02849a55f01bfa563174c5c47bf07c2370817)) +* change cli parser (wip) ([2009923](https://github.com/joolfe/postman-to-openapi/commit/20099237ac1a85d4945a3e19e1c147c4b8206c8e)) +* cli added to library ([5df5d9b](https://github.com/joolfe/postman-to-openapi/commit/5df5d9b5cc985b6418f2bb1ab44411dd7624b8d3)) +* files configured in package.json Close [#103](https://github.com/joolfe/postman-to-openapi/issues/103) ([0ac1cd2](https://github.com/joolfe/postman-to-openapi/commit/0ac1cd2901d63b59d9bd21f4983e86f6f79cb961)) +* husky version 6 ([1f39c49](https://github.com/joolfe/postman-to-openapi/commit/1f39c4968d2b23e17c935b90df85795b7493716c)) +* keep old husky config ([1d85167](https://github.com/joolfe/postman-to-openapi/commit/1d851677c39bd4b977cd4f9ddeea79bbd649e37a)) +* simple cli called p2o ([a4cea3f](https://github.com/joolfe/postman-to-openapi/commit/a4cea3f9a4e99b14978039d46333a303e7e6919c)) +* using aslant instead standard.js Close [#94](https://github.com/joolfe/postman-to-openapi/issues/94) ([4ab6aef](https://github.com/joolfe/postman-to-openapi/commit/4ab6aef7fb51328573b387fed920ff5d90abee5c)) +* **wip:** first version of cli ([a259287](https://github.com/joolfe/postman-to-openapi/commit/a259287745556fad13e5e6d0399f47d0e4719abb)) + + +### Bug Fixes + +* avoid fail `body.raw` is empty string Close [#101](https://github.com/joolfe/postman-to-openapi/issues/101) ([1c376cf](https://github.com/joolfe/postman-to-openapi/commit/1c376cff2bc77420ae96fb188d27bac94f0c349b)) +* some adaptions to use husky ([39d1a35](https://github.com/joolfe/postman-to-openapi/commit/39d1a35da9eae56a560d61102229249f31daaefe)) + + +### Build System + +* update some deps ([22c0086](https://github.com/joolfe/postman-to-openapi/commit/22c0086ec58c38e2763374bb93533e0650a1834a)) + + +### Code Refactoring + +* only one file and ass more test ([1c440da](https://github.com/joolfe/postman-to-openapi/commit/1c440da2b3f93ce2085026a7bbc0bb905a94efc3)) + + +### Documentation + +* add cli references ([739ea64](https://github.com/joolfe/postman-to-openapi/commit/739ea64f289d61706f7ddb644a619fe6bfc65eaf)) +* update changelog ([7813e7c](https://github.com/joolfe/postman-to-openapi/commit/7813e7c1ffd58bbe9b2325b8de69f288deca8ace)) + ### [1.7.3](https://github.com/joolfe/postman-to-openapi/compare/1.7.1...1.7.3) (2021-04-24) diff --git a/README.md b/README.md index cf03b06..e42b3dc 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,6 @@ Or in other words, transform [this specification](https://schema.getpostman.com/ [![docs](https://img.shields.io/badge/docs-here-yellow)](https://joolfe.github.io/postman-to-openapi/) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com) - ## Installation Using `npm`: @@ -28,8 +27,16 @@ Using `yarn`: yarn add postman-to-openapi ``` +To install as a `cli` just + +```bash +npm i postman-to-openapi -g +``` + ## Quick Usage +As a library + ```js // Require Package const postmanToOpenApi = require('postman-to-openapi') @@ -59,6 +66,12 @@ postmanToOpenApi(postmanCollection, outputFile, { defaultTag: 'General' }) }) ``` +As a cli + +```bash +p2o ./path/to/PostmantoCollection.json -f ./path/to/result.yml -o ./path/to/options.json +``` + ## Documentation All features, usage instructions and help can be found in the [Documentation page](https://joolfe.github.io/postman-to-openapi/) diff --git a/bin/cli.js b/bin/cli.js new file mode 100755 index 0000000..227ea01 --- /dev/null +++ b/bin/cli.js @@ -0,0 +1,50 @@ +#!/usr/bin/env node + +const { program } = require('commander') +const { version } = require('../package.json') +const postmanToOpenApi = require('../lib') +const { promises: { readFile } } = require('fs') + +const additionalHelp = ` + +Example calls: + $ p2o ./path/to/PostmantoCollection.json -f ./path/to/result.yml -o ./path/to/options.json + +For more info about how to use it visit our documentation in +` + +program + .version(version, '-v, --vers', 'Output the current version of the library.') + .name('p2o') + .usage(' [options]') + .addHelpText('after', additionalHelp) + .arguments('') + .description('Transform a postman collection to OpenAPI specification yml.', { + collection: 'Relative path to the Postman collection json file' + }) + .option('-f, --file ', 'Relative path to the file where result will be saved. If empty result will be returned by cli.') + .option('-o, --options ', 'Relative path to json file that contain the optional parameters for the transformation.') + .action(async (collection, { file, options }, command) => { + try { + const parsedOptions = await parseOptions(options) + const result = await postmanToOpenApi(collection, file, parsedOptions) + console.info(result) + } catch (err) { + throw new Error(err) + } + }) + +program + .parseAsync() + .catch(err => { + process.exitCode = 1 + console.error(err.message) + }) + +async function parseOptions (optionsPath) { + try { + return optionsPath ? JSON.parse(await readFile(optionsPath)) : {} + } catch (err) { + throw new Error(`invalid "options" parameter -> ${err.message}`) + } +} diff --git a/docs/index.md b/docs/index.md index ef87f90..c13bde1 100644 --- a/docs/index.md +++ b/docs/index.md @@ -15,20 +15,21 @@ ## Features at a glance -- Postman Collection v2.1 and v2.0. -- OpenApi 3.0 -- Basic info API from Postman info or customizable. -- Basic method conversion (GET, POST, PUT...). -- Support Postman folders as tags. -- Transform query, headers and path parameters (description, required...). -- Postman variables as Path parameters. -- Automatic infer types from query and headers parameters. -- Support Json and Text body formats. -- Global Authorization parse or by configuration (Basic and Bearer). -- Contact and License from variables or by configuration. -- Provide meta-information as a markdown table. -- Path depth configuration. -- Response status code parse from test. +* Postman Collection v2.1 and v2.0. +* OpenApi 3.0 +* 🆕 Cli available +* Basic info API from Postman info or customizable. +* Basic method conversion (GET, POST, PUT...). +* Support Postman folders as tags. +* Transform query, headers and path parameters (description, required...). +* Postman variables as Path parameters. +* Automatic infer types from query and headers parameters. +* Support Json and Text body formats. +* Global Authorization parse or by configuration (Basic and Bearer). +* Contact and License from variables or by configuration. +* Provide meta-information as a markdown table. +* Path depth configuration. +* Response status code parse from test. See [Features](#features) section for more details about how to use each of this features. @@ -37,17 +38,25 @@ See [Features](#features) section for more details about how to use each of this # Install +To use local in your Node.js project as a library + ```bash npm i postman-to-openapi --save ``` -To use as a cli coming soon... +To use as a cli + +```bash +npm i postman-to-openapi -g +```
# Usage +## As library + Use the library is as easy as use a single method `async postmanToOpenApi(inputPath, outputPath, options)`, the parameters are: | Param | Description | @@ -86,6 +95,20 @@ postmanToOpenApi(postmanCollection, outputFile, { defaultTag: 'General' }) }) ``` +## As cli + +After install just need to + +```bash +p2o ./path/to/PostmantoCollection.json -f ./path/to/result.yml -o ./path/to/options.json +``` + +All the field described in [options](#options) can be provided and used in the cli, for more info an all the available options just check the cli help + +```bash +p2o -h +``` + ## Options The third parameter used in the library method is an `options` object containing the optional parameters for the transformation, the allowed parameters are: diff --git a/package-lock.json b/package-lock.json index 72f3d35..9d4ca75 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,28 +1,36 @@ { "name": "postman-to-openapi", - "version": "1.7.3", + "version": "1.8.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "version": "1.7.3", + "version": "1.8.0", "license": "MIT", "dependencies": { + "commander": "^7.2.0", "js-yaml": "^4.1.0", "marked": "^2.0.3" }, + "bin": { + "p2o": "bin/cli.js" + }, "devDependencies": { "@commitlint/cli": "^12.1.1", "@commitlint/config-conventional": "^12.1.1", "conventional-changelog-cli": "^2.1.1", - "eslint": "^7.24.0", + "eslint": "^7.25.0", "eslint-config-standard": "^16.0.2", "eslint-plugin-import": "^2.22.1", "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^5.1.0", + "execa": "^5.0.0", "husky": "^6.0.0", "mocha": "^8.3.2", "nyc": "^15.1.0" + }, + "engines": { + "node": ">=10 <15" } }, "node_modules/@babel/code-frame": { @@ -512,9 +520,6 @@ }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@commitlint/top-level/node_modules/locate-path": { @@ -527,9 +532,6 @@ }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@commitlint/top-level/node_modules/p-limit": { @@ -542,9 +544,6 @@ }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@commitlint/top-level/node_modules/p-locate": { @@ -557,9 +556,6 @@ }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@commitlint/types": { @@ -1194,6 +1190,14 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -1939,9 +1943,9 @@ } }, "node_modules/eslint": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.24.0.tgz", - "integrity": "sha512-k9gaHeHiFmGCDQ2rEfvULlSLruz6tgfA8DEn+rY9/oYPFFTlz55mM/Q/Rij1b2Y42jwZiK3lXvNTw6w6TXzcKQ==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.25.0.tgz", + "integrity": "sha512-TVpSovpvCNpLURIScDRB6g5CYu/ZFq9GfX2hLNIV4dSBKxIWojeDODvYl3t0k0VtMxYeR8OXPCFE5+oHMlGfhw==", "dev": true, "dependencies": { "@babel/code-frame": "7.12.11", @@ -1987,9 +1991,6 @@ }, "engines": { "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-config-standard": { @@ -2406,9 +2407,6 @@ "dev": true, "engines": { "node": "^10.12.0 || >=12.0.0" - }, - "peerDependencies": { - "eslint": "^7.0.0" } }, "node_modules/eslint-scope": { @@ -2618,6 +2616,26 @@ "node": ">=0.10.0" } }, + "node_modules/execa": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz", + "integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -3159,6 +3177,15 @@ "node": ">=10" } }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/git-raw-commits": { "version": "2.0.10", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.10.tgz", @@ -3408,6 +3435,15 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, "node_modules/husky": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/husky/-/husky-6.0.0.tgz", @@ -3415,9 +3451,6 @@ "dev": true, "bin": { "husky": "lib/bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/typicode" } }, "node_modules/ignore": { @@ -3943,10 +3976,8 @@ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "dependencies": { + "graceful-fs": "^4.1.6", "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" } }, "node_modules/jsonparse": { @@ -4178,6 +4209,21 @@ "node": ">=10" } }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -4464,6 +4510,18 @@ "node": ">=0.10.0" } }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/nyc": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", @@ -4754,6 +4812,18 @@ "wrappy": "1" } }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -5527,6 +5597,15 @@ "node": ">=0.10.0" } }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/strip-indent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", @@ -7115,6 +7194,11 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" + }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -7708,9 +7792,9 @@ "dev": true }, "eslint": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.24.0.tgz", - "integrity": "sha512-k9gaHeHiFmGCDQ2rEfvULlSLruz6tgfA8DEn+rY9/oYPFFTlz55mM/Q/Rij1b2Y42jwZiK3lXvNTw6w6TXzcKQ==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.25.0.tgz", + "integrity": "sha512-TVpSovpvCNpLURIScDRB6g5CYu/ZFq9GfX2hLNIV4dSBKxIWojeDODvYl3t0k0VtMxYeR8OXPCFE5+oHMlGfhw==", "dev": true, "requires": { "@babel/code-frame": "7.12.11", @@ -8156,8 +8240,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.1.0.tgz", "integrity": "sha512-NGmI6BH5L12pl7ScQHbg7tvtk4wPxxj8yPHH47NvSmMtFneC077PSeY3huFj06ZWZvtbfxSPt3RuOQD5XcR4ng==", - "dev": true, - "requires": {} + "dev": true }, "eslint-scope": { "version": "5.1.1", @@ -8263,6 +8346,23 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, + "execa": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz", + "integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -8694,6 +8794,12 @@ "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", "dev": true }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, "git-raw-commits": { "version": "2.0.10", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.10.tgz", @@ -8882,6 +8988,12 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, "husky": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/husky/-/husky-6.0.0.tgz", @@ -9478,6 +9590,18 @@ } } }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, "min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -9704,6 +9828,15 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, "nyc": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", @@ -9939,6 +10072,15 @@ "wrappy": "1" } }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -10557,6 +10699,12 @@ "is-utf8": "^0.2.0" } }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, "strip-indent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", diff --git a/package.json b/package.json index c6aea0d..0110140 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,11 @@ { "name": "postman-to-openapi", - "version": "1.7.3", + "version": "1.8.0", "description": "Convert postman collection to OpenAPI spec", "main": "lib/index.js", + "bin": { + "p2o": "./bin/cli.js" + }, "scripts": { "lint": "eslint **/*.js", "lint:fix": "eslint **/*.js --fix", @@ -13,6 +16,10 @@ "changelog": "conventional-changelog --config ./changelog.config.js -i CHANGELOG.md -s", "prepare": "husky install" }, + "files": [ + "bin/*", + "lib/*" + ], "repository": { "type": "git", "url": "git+https://github.com/joolfe/postman-to-openapi.git" @@ -38,11 +45,12 @@ "@commitlint/cli": "^12.1.1", "@commitlint/config-conventional": "^12.1.1", "conventional-changelog-cli": "^2.1.1", - "eslint": "^7.24.0", + "eslint": "^7.25.0", "eslint-config-standard": "^16.0.2", "eslint-plugin-import": "^2.22.1", "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^5.1.0", + "execa": "^5.0.0", "husky": "^6.0.0", "mocha": "^8.3.2", "nyc": "^15.1.0" @@ -52,11 +60,15 @@ "@commitlint/config-conventional" ] }, + "engines": { + "node": ">=10 <15" + }, "nyc": { "all": true, "include": [ "lib/**/*.js", - "test/**/*.js" + "test/**/*.js", + "bin/**/*.js" ], "exclude": [], "reporter": [ @@ -71,6 +83,7 @@ "check-coverage": true }, "dependencies": { + "commander": "^7.2.0", "js-yaml": "^4.1.0", "marked": "^2.0.3" }, diff --git a/test/cli.spec.js b/test/cli.spec.js new file mode 100644 index 0000000..dc5441c --- /dev/null +++ b/test/cli.spec.js @@ -0,0 +1,92 @@ +'use strict' + +const { describe, it, afterEach } = require('mocha') +const { readFileSync, existsSync, unlinkSync } = require('fs') +const { equal, rejects, ok } = require('assert').strict +const execa = require('execa') + +const cliPath = './bin/cli.js' +const COLLECTION_BASIC = './test/resources/input/v21/PostmantoOpenAPI.json' +const COLLECTION_SIMPLE = './test/resources/input/v21/SimplePost.json' +const OPTIONS_INFO = './test/resources/input/options.json' +const INVALID_OPTIONS_INFO = './test/resources/input/invalidOptions.txt' +const EXPECTED_INFO_OPTS = readFileSync('./test/resources/output/InfoOpts.yml', 'utf8') +const EXPECTED_BASIC = readFileSync('./test/resources/output/Basic.yml', 'utf8') +const OUTPUT_PATH = './openAPIRes.yml' +const HELP_OUTPUT = readFileSync('./test/resources/console/help.txt', 'utf8') + +const { version } = require('../package.json') + +describe('Cli specs', function () { + afterEach('remove file', function () { + if (existsSync(OUTPUT_PATH)) { + unlinkSync(OUTPUT_PATH) + } + }) + + it('should transform correctly a basic collection (HP)', async function () { + const { stdout } = await execa('node', [cliPath, COLLECTION_BASIC]) + equal(stdout, EXPECTED_BASIC) + }) + + it('should return an error when collection argument is not provided', async function () { + await rejects(execa('node', [cliPath]), { + name: 'Error', + stderr: "error: missing required argument 'collection'", + exitCode: 1 + }) + }) + + it('should print an error when collection file doesn\'t exist', async function () { + await rejects(execa('node', [cliPath, './none/file.json']), { + name: 'Error', + stderr: "Error: ENOENT: no such file or directory, open './none/file.json'", + exitCode: 1 + }) + }) + + it('should print an error when result file cannot be created', async function () { + await rejects(execa('node', [cliPath, COLLECTION_BASIC, '-f', './no_exist/result.yml']), { + name: 'Error', + stderr: "Error: ENOENT: no such file or directory, open './no_exist/result.yml'", + exitCode: 1 + }) + }) + + it('should transform and write into a file the output (HP)', async function () { + const { stdout } = await execa('node', [cliPath, COLLECTION_BASIC, '-f', OUTPUT_PATH]) + ok(existsSync(OUTPUT_PATH)) + equal(stdout, EXPECTED_BASIC) + }) + + it('should transform correctly a basic collection when using option file (HP)', async function () { + const { stdout } = await execa('node', [cliPath, COLLECTION_SIMPLE, '-o', OPTIONS_INFO]) + equal(stdout, EXPECTED_INFO_OPTS) + }) + + it('should print an error when "options" file doesn\'t exist', async function () { + await rejects(execa('node', [cliPath, COLLECTION_SIMPLE, '-o', './no_exist/options.json']), { + name: 'Error', + stderr: "Error: invalid \"options\" parameter -> ENOENT: no such file or directory, open './no_exist/options.json'", + exitCode: 1 + }) + }) + + it('should print an error when options file is not a valid json', async function () { + await rejects(execa('node', [cliPath, COLLECTION_SIMPLE, '-o', INVALID_OPTIONS_INFO]), { + name: 'Error', + stderr: 'Error: invalid "options" parameter -> Unexpected token i in JSON at position 6', + exitCode: 1 + }) + }) + + it('should print correctly the version of the cli', async function () { + const { stdout } = await execa('node', [cliPath, '-v']) + equal(stdout, version) + }) + + it('should print correctly help command', async function () { + const { stdout } = await execa('node', [cliPath, '-h']) + equal(stdout, HELP_OUTPUT) + }) +}) diff --git a/test/resources/console/help.txt b/test/resources/console/help.txt new file mode 100644 index 0000000..302a915 --- /dev/null +++ b/test/resources/console/help.txt @@ -0,0 +1,20 @@ +Usage: p2o [options] + +Transform a postman collection to OpenAPI specification yml. + +Arguments: + collection Relative path to the Postman collection json file + +Options: + -v, --vers Output the current version of the library. + -f, --file Relative path to the file where result will be + saved. If empty result will be returned by cli. + -o, --options Relative path to json file that contain the optional + parameters for the transformation. + -h, --help display help for command + + +Example calls: + $ p2o ./path/to/PostmantoCollection.json -f ./path/to/result.yml -o ./path/to/options.json + +For more info about how to use it visit our documentation in diff --git a/test/resources/input/invalidOptions.txt b/test/resources/input/invalidOptions.txt new file mode 100644 index 0000000..7541589 --- /dev/null +++ b/test/resources/input/invalidOptions.txt @@ -0,0 +1,8 @@ +{ + info": { + "title": "Options title", + "version: "6.0.7-beta", + "description": "Description from options", + "termsOfService": "http://tos.myweb.com" + } +} \ No newline at end of file diff --git a/test/resources/input/options.json b/test/resources/input/options.json new file mode 100644 index 0000000..f03c51e --- /dev/null +++ b/test/resources/input/options.json @@ -0,0 +1,8 @@ +{ + "info": { + "title": "Options title", + "version": "6.0.7-beta", + "description": "Description from options", + "termsOfService": "http://tos.myweb.com" + } +} \ No newline at end of file diff --git a/test/resources/options/info.json b/test/resources/options/info.json new file mode 100644 index 0000000..da192bb --- /dev/null +++ b/test/resources/options/info.json @@ -0,0 +1,8 @@ +{ + "info": { + "title": "Options title", + "version": "6.0.7-beta", + "description": "Description from options", + "termsOfService": "http://tos.myweb.com" + } + } \ No newline at end of file