oas 19.0.3 → 20.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.alexignore ADDED
@@ -0,0 +1 @@
1
+ CHANGELOG.md
package/.alexrc ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "profanitySureness": 1
3
+ }
package/CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
1
+ ## 20.0.0 (2022-10-28)
2
+
3
+ > **BREAKING CHANGE**
4
+ >
5
+ > This library is shifting focus to being soley focused on OpenAPI tooling and longer ships a CLI wrapper for creating OpenAPI definitions. If you need an OpenAPI (or Swagger) definition for your API we recommend checking out the API editing experience within [ReadMe](https://readme.com), manually maintaining JSON/YAML files (it sounds worse than it actually is), or the language-agnostic [swagger-inline](https://npm.im/swagger-inline).
6
+
7
+ * chore(deps-dev): bumping dev deps ([371e041](https://github.com/readmeio/oas/commit/371e041))
8
+ * feat: sunsetting the cli (#702) ([c1b2728](https://github.com/readmeio/oas/commit/c1b2728)), closes [#702](https://github.com/readmeio/oas/issues/702)
9
+ * docs: adding a hero image for the readme ([26d6018](https://github.com/readmeio/oas/commit/26d6018))
10
+
11
+
12
+
13
+ ## <small>19.0.4 (2022-10-27)</small>
14
+
15
+ * fix: edgecase where we wouldn't always create valid operationIds (#701) ([df160c2](https://github.com/readmeio/oas/commit/df160c2)), closes [#701](https://github.com/readmeio/oas/issues/701)
16
+
17
+
18
+
1
19
  ## <small>19.0.3 (2022-10-27)</small>
2
20
 
3
21
  * fix: various compatibility issues with `api` codegen (#700) ([01a6554](https://github.com/readmeio/oas/commit/01a6554)), closes [#700](https://github.com/readmeio/oas/issues/700)
package/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2020 ReadMe
3
+ Copyright (c) 2022 ReadMe
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,10 +1,43 @@
1
- # oas
2
-
3
- Working with OpenAPI definitions is hard. This makes it easier.
4
-
5
- [![Build](https://github.com/readmeio/oas/workflows/CI/badge.svg)](https://github.com/readmeio/oas/) [![](https://img.shields.io/npm/v/oas)](https://npm.im/oas)
6
-
7
- [![](https://d3vv6lp55qjaqc.cloudfront.net/items/1M3C3j0I0s0j3T362344/Untitled-2.png)](https://readme.com)
1
+ <p align="center">
2
+ <a href="https://npm.im/oas">
3
+ <img src="https://raw.githubusercontent.com/readmeio/oas/main/.github/hero.png" alt="oas" />
4
+ </a>
5
+ </p>
6
+
7
+ <p align="center">
8
+ Comprehensive tooling for working with OpenAPI definitions
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://npm.im/oas"><img src="https://img.shields.io/npm/v/oas.svg?style=for-the-badge" alt="NPM Version"></a>
13
+ <a href="https://npm.im/oas"><img src="https://img.shields.io/node/v/oas.svg?style=for-the-badge" alt="Node Version"></a>
14
+ <a href="https://npm.im/oas"><img src="https://img.shields.io/npm/l/oas.svg?style=for-the-badge" alt="MIT License"></a>
15
+ <a href="https://github.com/readmeio/oas"><img src="https://img.shields.io/github/workflow/status/readmeio/oas/CI.svg?style=for-the-badge" alt="Build status"></a>
16
+ </p>
17
+
18
+ `oas` is the library that we've built at [ReadMe](https://readme.com) for powering everything we do related to [OpenAPI](https://www.openapis.org/); from our [Reference Guides](https://readme.com/documentation), to our [Metrics product](https://readme.com/metrics) or to other in-house tooling like [code generation](https://npm.im/@readme/oas-to-snippet), [request execution](https://npm.im/@readme/oas-to-har), and [SDK code generation](https://api.readme.dev/).
19
+
20
+ ---
21
+
22
+ - [Installation](https://api.readme.dev/docs/installation)
23
+ - [Usage](#usage)
24
+ - [OpenAPI definitions](#openapi-definitions)
25
+ - [General](#general)
26
+ - [Operations](#operations)
27
+ - [Servers](#servers)
28
+ - [Specification Extensions](#specification-extensions)
29
+ - [User Authentication](#user-authentication)
30
+ - [Operations](#operations-1)
31
+ - [General](#general-1)
32
+ - [Callbacks](#callbacks)
33
+ - [Request Body](#request-body)
34
+ - [Responses](#responses)
35
+ - [Security](#security)
36
+ - [Specification Extensions](#specification-extensions-1)
37
+ - [Callbacks](#callbacks)
38
+ - [General](#general-2)
39
+ - [Webhooks](#webhooks)
40
+ - [FAQ](#faq)
8
41
 
9
42
  ## Installation
10
43
 
@@ -12,62 +45,201 @@ Working with OpenAPI definitions is hard. This makes it easier.
12
45
  npm install oas
13
46
  ```
14
47
 
15
- ## CLI
16
- The CLI tool makes creating API definition files easier. It currently supports [OpenAPI 3.x](https://swagger.io/specification/) and [Swagger 2.0](https://swagger.io/specification/v2/) documents.
48
+ ## Usage
17
49
 
18
- ### Usage
50
+ > **Note**
51
+ > If you need to use this library within a browser you'll likely need to use a bundler like [Webpack](https://webpack.js.org/) or [Rollup](https://rollupjs.org/).
19
52
 
20
- Go to a directory with your API, and type:
53
+ `oas` offers a main `Oas` class, which will be your main entrypoint for using the library.
21
54
 
22
- ```
23
- oas init
55
+ ```js
56
+ import Oas from 'oas';
57
+ import petstoreSpec from '@readme/oas-examples/3.0/json/petstore.json';
58
+
59
+ const petstore = new Oas(petstoreSpec);
24
60
  ```
25
61
 
26
- It will walk you through how to document your API with a OpenAPI 3.0 Spec.
62
+ Here the `Oas` constructor takes a JSON API definition (`petstoreSpec`). All API definitions you feed it must be JSON and must be an OpenAPI definition. If you have a YAML or Swagger definition you will need to convert it (our [oas-normalize](https://npm.im/oas-normalize) library can do this for you). And if you're in a CJS or non-`import` environment you can pull the library in with `require('oas').default`.
27
63
 
28
- #### Commands
64
+ From here, the following APIs are at your disposal.
29
65
 
30
- ```
31
- Usage: oas <command>
66
+ ### OpenAPI definitions
32
67
 
33
- $ oas init Create a new OpenAPI definition
34
- $ oas help Learn what you can do with oas
35
- $ oas endpoint Learn how to document an endpoint
36
- $ oas generate [oas.json] Output your OpenAPI definition (use --pretty for colors)
37
- $ oas validate [oas.json] Validate your OpenAPI definition
38
- ```
68
+ Because this library has full TypeScript types and docblocks this README is not intended to be full documentation so consult the individual method docblocks if you need more information on a specific method.
39
69
 
40
- ### Swagger Inline
70
+ #### General
41
71
 
42
- `oas` uses [swagger-inline](https://github.com/readmeio/swagger-inline) which allows you include a little OpenAPI snippet in a comment above your code, and collects them all together into one OpenAPI file:
72
+ <!-- prettier-ignore-start -->
73
+ | Method | Description |
74
+ | :--- | :--- |
75
+ | `#dereference()` | Dereference the current OpenAPI definition. Note that this will ignore circular references. |
76
+ | `#getDefinition()` | Retrieve the OpenAPI definition that was fed into the `Oas` constructor. |
77
+ | `#getTags()` | Retrieve an array of all tags that exist within the API definition and are set on operations. |
78
+ | `#getPaths()` | Retrieve every operation that exists within the API definition. This returns an array of instances of the `Operation` class. |
79
+ | `#getVersion()` | Retrieve the OpenAPI version that this API definition is targeted for. |
80
+ | `#getWebhooks()` | Retrieve every webhook operation that exists within the API definition. This returns an array of instances of the `Webhook` class. |
81
+ | `#init()` | An alternative for `new Oas()` that you can use if the typing on the `Oas` constructor gives you trouble. Typing OpenAPI definitions is hard! |
82
+ <!-- prettier-ignore-end -->
43
83
 
44
- ```js
45
- /*
46
- * @oas [get] /pet/{petId}
47
- * description: "Returns all pets from the system that the user has access to"
48
- * parameters:
49
- * - (path) petId=hi* {String} The pet ID
50
- * - (query) limit {Integer:int32} The number of resources to return
51
- */
52
- route.get("/pet/:petId", pet.show);
53
- ```
84
+ #### Operations
54
85
 
55
- You need to start with `@oas [method] path`, but everything below it is a valid [Path Definition](http://swagger.io/specification/#pathItemObject).
86
+ <!-- prettier-ignore-start -->
87
+ | Method | Description |
88
+ | :--- | :--- |
89
+ | `#findOperation()` | Discover an operation with the current OpenAPI definition that matches a given URL and HTTP method. |
90
+ | `#findOperationWithoutMethod()` | Like `oas.findOperation()` but without supplying an HTTP method. |
91
+ | `#getOperation()` | Same as `oas.findOperation()` but this returns an instance of the `Operation` class. |
92
+ | `#operation()` | Retrieve an instance of the `Operation` or `Webhook` classes for a given path and HTTP method. |
93
+ <!-- prettier-ignore-end -->
56
94
 
57
- You can also do **inline parameters**, which are shorthand for parameters. They aren't valid OpenAPI properties but `swagger-inline` knows how to compile them:
95
+ #### Servers
58
96
 
59
- ```
60
- - (in) name=default* {type:format} Description
61
- ```
97
+ <!-- prettier-ignore-start -->
98
+ | Method | Description |
99
+ | :--- | :--- |
100
+ | `#defaultVariables()` | Retrieve the default server variables for a specific server URL, while also potentially factoring in user data. You can specify user variable data to the `Oas` constructor. Check out [Using Variables in Documentation](https://docs.readme.com/docs/user-data-options#using-variables-in-documentation) for some background on how we use this. |
101
+ | `#replaceUrl()` | Replace a given templated server URL with supplied server variable data. |
102
+ | `#splitUrl()` | Chunk out a specific server URL into its individual parts. |
103
+ | `#splitVariables` | Chunk out a given URL and if it matches a server URL in the OpenAPI file, extract the matched server variables that are present in the URL. |
104
+ | `#url()` | Retrive a fully composed server URL. You can optionally select which of the defined server URLs to use as well as specify server variable information. |
105
+ | `#variables()` | Retrieve all server variables that a specific server URL in the definition has. |
106
+ <!-- prettier-ignore-end -->
107
+
108
+ #### Specification Extensions
109
+
110
+ <!-- prettier-ignore-start -->
111
+ | Method | Description |
112
+ | :--- | :--- |
113
+ | `#getExtension()` | Retrieve a given [specification extension](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#specificationExtensions) if it exists at the root of the API definition. |
114
+ | `#hasExtension()` | Determine if a given [specification extension](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#specificationExtensions) exists on the root of the API definition. |
115
+ <!-- prettier-ignore-end -->
116
+
117
+ #### User Authentication
118
+
119
+ <!-- prettier-ignore-start -->
120
+ | Method | Description |
121
+ | :--- | :--- |
122
+ | `#getAuth()` | Retrieve the appropriate API keys for the current OpenAPI definition from an object of user data. Check out [Using Variables in Documentation](https://docs.readme.com/docs/user-data-options#using-variables-in-documentation) for some background on how we use this. |
123
+ <!-- prettier-ignore-end -->
62
124
 
63
- ## Tooling
64
- This library also exposes a set of tooling to help you manage OpenAPI definitions. You can access it by loading:
125
+ ---
126
+
127
+ ### Operations
128
+
129
+ For your convenience, the entrypoint into the `Operation` class should generally always be through `Oas.operation()`. For example:
65
130
 
66
131
  ```js
67
132
  import Oas from 'oas';
68
- // or: const Oas = require('oas').default;
69
- ```
133
+ import petstoreSpec from '@readme/oas-examples/3.0/json/petstore.json';
70
134
 
71
- Also exposed within the main `oas` export is an `Operation` class that can help you manage and retrieve specific data from an API operation.
135
+ const petstore = new Oas(petstoreSpec);
136
+ const operation = petstore.operation('/pet', 'post');
137
+ ```
72
138
 
73
- > If you need to use this library within a browser you'll likely need to use a bundler like [Webpack](https://webpack.js.org/) or [Rollup](https://rollupjs.org/).
139
+ #### General
140
+
141
+ <!-- prettier-ignore-start -->
142
+ | Method | Description |
143
+ | :--- | :--- |
144
+ | `#getContentType()` | Retrieve the primary request body content type. If multiple are present, prefer whichever is JSON-compliant. |
145
+ | `#getDescription()` | Retrieve the `description` that's set on this operation. This supports common descriptions that may be set at the [path item level](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#pathItemObject). |
146
+ | `#getOperationId()` | Retrieve the `operationId` that's present on the operation, and if one is not present one will be created based off the method + path and returned instead. |
147
+ | `#hasOperationId()` | Determine if the operation has an `operationId` present. |
148
+ | `#isDeprecated()` | Determine if this operation is marked as deprecated. |
149
+ | `#isFormUrlEncoded()` | Determine if this operation requires its payload to be delivered as `application/x-www-form-urlencoded`. |
150
+ | `#isJson()` | Determine if this operation requires its payload to be delivered as JSON. |
151
+ | `#isMultipart()` | Determine if this operation requires its data to be sent as a multipart payload. |
152
+ | `#isXml()` | Determine if this operation requires its data to be sent as XML. |
153
+ | `#getHeaders()` | Retrieve all headers that can either be sent for or returned from this operation. This includes header-based authentication schemes, common header parameters, and request body and response content types. |
154
+ | `#getSummary()` | Retrieve the `summary` that's set on this operation. This supports common summaries that may be set at the [path item level](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#pathItemObject). |
155
+ | `#getTags()` | Retrieve all tags, and [their metadata](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#tagObject), that exist on this operation. |
156
+ <!-- prettier-ignore-end -->
157
+
158
+ #### Callbacks
159
+
160
+ <!-- prettier-ignore-start -->
161
+ | Method | Description |
162
+ | :--- | :--- |
163
+ | `#getCallback()` | Retrieve a specific callback on this operation. This will return an instance of the `Callback` class. |
164
+ | `#getCallbackExamples()` | Retrieve an array of all calback examples that this operation has defined. |
165
+ | `#getCallbacks()` | Retrieve all callbacks that this operation has. Similar to `Oas.getPaths()` returning an array of `Operation` instances this will return an array of `Callback` instances. |
166
+ | `#hasCallbacks()` | Determine if this operation has any callbacks defined. |
167
+ <!-- prettier-ignore-end -->
168
+
169
+ #### Parameters
170
+
171
+ > **Note**
172
+ > All parameter accessors here support, and will automatically retrieve and handle, common parameters that may be set at the [path item level](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#pathItemObject).
173
+
174
+ <!-- prettier-ignore-start -->
175
+ | Method | Description |
176
+ | :--- | :--- |
177
+ | `#getParameters()` | Retrieve all parameters that may be used with on this operation. |
178
+ | `#getParametersAsJSONSchema()` | Retrieve and convert the operations parameters into an array of JSON Schema schemas for each available type of parameter available on the operation: `path`, `query`, `body`, `cookie`, `formData`, and `header`. |
179
+ | `#hasParameters()` | Determine if the operation has any parameters to send. |
180
+ | `#hasRequiredParameters()` | Determine if any of the parameters on this operation are required. |
181
+ <!-- prettier-ignore-end -->
182
+
183
+ #### Request Body
184
+
185
+ <!-- prettier-ignore-start -->
186
+ | Method | Description |
187
+ | :--- | :--- |
188
+ | `#getRequestBody()` | Retrieve the raw request body object for a given content type. If none is specified it will return either the first that's JSON-like, or the first defined. |
189
+ | `#getRequestBodyExamples()` | Retrieve an array of all request body examples that this operation has defined. |
190
+ | `#getRequestBodyMediaTypes()` | Retrieve a list of all the media/content types that the operation can accept a request body payload for. |
191
+ | `#hasRequestBody()` | Determine if this operation has a request body defined. |
192
+ <!-- prettier-ignore-end -->
193
+
194
+ #### Responses
195
+
196
+ <!-- prettier-ignore-start -->
197
+ | Method | Description |
198
+ | :--- | :--- |
199
+ | `#getResponseAsJSONSchema()` | Retrive and convert a response on this operation into JSON Schema. |
200
+ | `#getResponseByStatusCode()` | Retrieve the raw response object for a given status code. |
201
+ | `#getResponseExamples()` | Retrieve an array of all response examples that this operation has defined. |
202
+ | `#getResponseStatusCodes()` | Retrieve all status codes that this operation may respond with. |
203
+ | `#hasRequiredRequestBody()` | Determine if this operation has a required request body. |
204
+ <!-- prettier-ignore-end -->
205
+
206
+ #### Security
207
+
208
+ <!-- prettier-ignore-start -->
209
+ | Method | Description |
210
+ | :--- | :--- |
211
+ | `#getSecurity()` | Return all security requirements that are applicable for either this operation, or if the operation has none specific to it, then for the entire API. |
212
+ | `#getSecurityWithTypes()` | Return a collection of all security schemes applicable to this operation (using `#getSecurity()`), grouped by how the security should be handled (either AND or OR auth requirements). |
213
+ | `#prepareSecurity` | Return an object of every security scheme that _can_ be used on this operation, indexed by the type of security scheme it is (eg. `Basic`, `OAuth2`, `APIKey`, etc.). |
214
+ <!-- prettier-ignore-end -->
215
+
216
+ #### Specification Extensions
217
+
218
+ <!-- prettier-ignore-start -->
219
+ | Method | Description |
220
+ | :--- | :--- |
221
+ | `#getExtension()` | Retrieve a given [specification extension](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#specificationExtensions) if it exists on this operation. |
222
+ | `#hasExtension()` | Determine if a given [specification extension](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#specificationExtensions) exists on this operation. |
223
+ <!-- prettier-ignore-end -->
224
+
225
+ ### Callbacks
226
+
227
+ The `Callback` class inherits `Operation` so every API available on instances of `Operation` is available here too. Much like `Operation`, we also support common parameters, summaries, and descriptions that may be set at the [path item level](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#pathItemObject) within a `callbacks` definition.
228
+
229
+ #### General
230
+
231
+ <!-- prettier-ignore-start -->
232
+ | Method | Description |
233
+ | :--- | :--- |
234
+ | `#getIdentifier()` | Retrieve the primary identifier of this callback. |
235
+ <!-- prettier-ignore-end -->
236
+
237
+ ### Webhooks
238
+
239
+ Because our `Webhook` class extends `Operation`, every API that's available on the [Operation](#operation) class is available on webhooks.
240
+
241
+ ## FAQ
242
+
243
+ #### Can I create an OpenAPI definition with this?
244
+
245
+ Though `oas` used to offer functionality related to this, it does no longer. If you need an OpenAPI (or Swagger) definition for your API we recommend checking out the API editing experience within [ReadMe](https://readme.com), manually maintaining JSON/YAML files (it sounds worse than it actually is), or the language-agnostic [swagger-inline](https://npm.im/swagger-inline).
package/dist/index.d.ts CHANGED
@@ -184,7 +184,7 @@ export default class Oas {
184
184
  getPaths(): Record<string, Record<RMOAS.HttpMethods, Operation | Webhook>>;
185
185
  /**
186
186
  * Returns the `webhooks` object that exists in this API definition but with every `method`
187
- * mapped to an instance of the `Operation` class.
187
+ * mapped to an instance of the `Webhook` class.
188
188
  *
189
189
  * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#oasObject}
190
190
  * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#openapi-object}
package/dist/index.js CHANGED
@@ -656,7 +656,7 @@ var Oas = /** @class */ (function () {
656
656
  };
657
657
  /**
658
658
  * Returns the `webhooks` object that exists in this API definition but with every `method`
659
- * mapped to an instance of the `Operation` class.
659
+ * mapped to an instance of the `Webhook` class.
660
660
  *
661
661
  * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#oasObject}
662
662
  * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#openapi-object}
@@ -59,8 +59,8 @@ export default class Operation {
59
59
  */
60
60
  getSecurity(): RMOAS.SecurityRequirementObject[];
61
61
  /**
62
- * Retrieve a collection of grouped security schemes. The inner array determines and-grouped
63
- * security schemes, the outer array determines or-groups.
62
+ * Retrieve a collection of grouped security schemes. The inner array determines AND-grouped
63
+ * security schemes, the outer array determines OR-groups.
64
64
  *
65
65
  * @see {@link https://swagger.io/docs/specification/authentication/#multiple}
66
66
  * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#security-requirement-object}
package/dist/operation.js CHANGED
@@ -108,7 +108,7 @@ var Operation = /** @class */ (function () {
108
108
  }
109
109
  // Favor JSON if it exists
110
110
  types.forEach(function (t) {
111
- if (t.match(/json/)) {
111
+ if (matches_mimetype_1["default"].json(t)) {
112
112
  _this.contentType = t;
113
113
  }
114
114
  });
@@ -140,8 +140,8 @@ var Operation = /** @class */ (function () {
140
140
  return this.schema.security || this.api.security || [];
141
141
  };
142
142
  /**
143
- * Retrieve a collection of grouped security schemes. The inner array determines and-grouped
144
- * security schemes, the outer array determines or-groups.
143
+ * Retrieve a collection of grouped security schemes. The inner array determines AND-grouped
144
+ * security schemes, the outer array determines OR-groups.
145
145
  *
146
146
  * @see {@link https://swagger.io/docs/specification/authentication/#multiple}
147
147
  * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#security-requirement-object}
@@ -309,8 +309,8 @@ var Operation = /** @class */ (function () {
309
309
  function sanitize(id) {
310
310
  return id
311
311
  .replace(/[^a-zA-Z0-9_]/g, '-') // Remove weird characters
312
- .replace(/^-|-$/g, '') // Don't start or end with -
313
- .replace(/--+/g, '-'); // Remove double --'s
312
+ .replace(/--+/g, '-') // Remove double --'s
313
+ .replace(/^-|-$/g, ''); // Don't start or end with -
314
314
  }
315
315
  var operationId;
316
316
  if (this.hasOperationId()) {
package/package.json CHANGED
@@ -1,22 +1,18 @@
1
1
  {
2
2
  "name": "oas",
3
- "version": "19.0.3",
4
- "description": "Working with OpenAPI definitions is hard. This makes it easier.",
3
+ "version": "20.0.0",
4
+ "description": "Comprehensive tooling for working with OpenAPI definitions",
5
5
  "license": "MIT",
6
6
  "author": "ReadMe <support@readme.io> (https://readme.com)",
7
7
  "main": "dist/index.js",
8
8
  "types": "dist/index.d.ts",
9
- "bin": {
10
- "oas": "bin/oas"
11
- },
12
9
  "engines": {
13
- "node": ">=12"
10
+ "node": ">=14"
14
11
  },
15
12
  "tags": [
16
13
  "api",
17
14
  "apis",
18
15
  "openapi",
19
- "swagger",
20
16
  "openapi initiative",
21
17
  "openapi specification",
22
18
  "openapi spec",
@@ -37,11 +33,13 @@
37
33
  "scripts": {
38
34
  "build": "tsc",
39
35
  "lint": "eslint . --ext .js,.ts",
36
+ "lint:docs": "npx alex .",
40
37
  "prebuild": "rm -rf dist/",
41
38
  "prepack": "npm run build",
42
39
  "prepare": "husky install",
43
40
  "pretest": "npm run lint",
44
- "prettier": "prettier --list-different --write \"./**/**.{js,ts}\"",
41
+ "prettier": "prettier --list-different \"./**/**.{js,ts,md}\"",
42
+ "prettier:write": "prettier --list-different --write \"./**/**.{js,ts,md}\"",
45
43
  "release": "npx conventional-changelog-cli -i CHANGELOG.md -s && git add CHANGELOG.md",
46
44
  "test": "tsc; jest --coverage",
47
45
  "test-watch": "tsc; jest --watch",
@@ -50,33 +48,26 @@
50
48
  "dependencies": {
51
49
  "@readme/json-schema-ref-parser": "^1.1.0",
52
50
  "@types/json-schema": "^7.0.11",
53
- "cardinal": "^2.1.1",
54
- "chalk": "^4.1.2",
55
- "glob": "^8.0.1",
56
- "inquirer": "^8.1.2",
57
51
  "json-schema-merge-allof": "^0.8.1",
58
- "json2yaml": "^1.1.0",
59
52
  "jsonpath": "^1.1.1",
60
53
  "jsonpointer": "^5.0.0",
61
54
  "memoizee": "^0.4.14",
62
- "minimist": "^1.2.0",
63
- "oas-normalize": "^7.0.0",
55
+ "oas-normalize": "^7.1.0",
64
56
  "openapi-types": "^12.0.0",
65
- "path-to-regexp": "^6.2.0",
66
- "swagger-inline": "^6.0.0"
57
+ "path-to-regexp": "^6.2.0"
67
58
  },
68
59
  "devDependencies": {
69
60
  "@commitlint/cli": "^17.0.2",
70
61
  "@commitlint/config-conventional": "^17.0.2",
71
- "@readme/eslint-config": "^10.0.0",
72
- "@readme/oas-examples": "^5.4.1",
62
+ "@readme/eslint-config": "^10.1.1",
63
+ "@readme/oas-examples": "^5.7.1",
73
64
  "@readme/openapi-parser": "^2.2.0",
74
65
  "@types/jest": "^28.1.6",
75
66
  "@types/json-schema-merge-allof": "^0.6.1",
76
67
  "@types/jsonpath": "^0.2.0",
77
68
  "@types/memoizee": "^0.4.6",
78
- "@types/node": "^18.8.2",
79
- "eslint": "^8.20.0",
69
+ "@types/node": "^18.11.7",
70
+ "eslint": "^8.26.0",
80
71
  "husky": "^8.0.1",
81
72
  "jest": "^28.1.3",
82
73
  "prettier": "^2.6.2",
package/src/index.ts CHANGED
@@ -695,7 +695,7 @@ export default class Oas {
695
695
 
696
696
  /**
697
697
  * Returns the `webhooks` object that exists in this API definition but with every `method`
698
- * mapped to an instance of the `Operation` class.
698
+ * mapped to an instance of the `Webhook` class.
699
699
  *
700
700
  * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#oasObject}
701
701
  * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#openapi-object}
package/src/operation.ts CHANGED
@@ -116,7 +116,7 @@ export default class Operation {
116
116
 
117
117
  // Favor JSON if it exists
118
118
  types.forEach(t => {
119
- if (t.match(/json/)) {
119
+ if (matchesMimeType.json(t)) {
120
120
  this.contentType = t;
121
121
  }
122
122
  });
@@ -155,8 +155,8 @@ export default class Operation {
155
155
  }
156
156
 
157
157
  /**
158
- * Retrieve a collection of grouped security schemes. The inner array determines and-grouped
159
- * security schemes, the outer array determines or-groups.
158
+ * Retrieve a collection of grouped security schemes. The inner array determines AND-grouped
159
+ * security schemes, the outer array determines OR-groups.
160
160
  *
161
161
  * @see {@link https://swagger.io/docs/specification/authentication/#multiple}
162
162
  * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#security-requirement-object}
@@ -342,8 +342,8 @@ export default class Operation {
342
342
  function sanitize(id: string) {
343
343
  return id
344
344
  .replace(/[^a-zA-Z0-9_]/g, '-') // Remove weird characters
345
- .replace(/^-|-$/g, '') // Don't start or end with -
346
- .replace(/--+/g, '-'); // Remove double --'s
345
+ .replace(/--+/g, '-') // Remove double --'s
346
+ .replace(/^-|-$/g, ''); // Don't start or end with -
347
347
  }
348
348
 
349
349
  let operationId;
package/tsconfig.json CHANGED
@@ -9,6 +9,5 @@
9
9
  "outDir": "./dist",
10
10
  "resolveJsonModule": true,
11
11
  },
12
- "include": ["./src/**/*"],
13
- "exclude": ["./src/cli/*"]
12
+ "include": ["./src/**/*"]
14
13
  }
package/bin/oas DELETED
@@ -1,8 +0,0 @@
1
- #! /usr/bin/env node
2
- const parseArgs = require('minimist')(process.argv.slice(2));
3
-
4
- const args = parseArgs._;
5
- const opts = Object.assign(parseArgs, {});
6
- delete opts._;
7
-
8
- require('../src/cli')(args, opts);
@@ -1,31 +0,0 @@
1
- const chalk = require('chalk');
2
-
3
- const utils = require('../lib/utils');
4
-
5
- exports.swagger = false;
6
- exports.desc = 'Learn how to document an endpoint';
7
- exports.weight = 3;
8
-
9
- exports.run = function () {
10
- console.log('You can document each API endpoint right alongside your code!');
11
- console.log('');
12
- console.log('Use the following syntax in a comment block above the the code:');
13
- console.log('');
14
-
15
- console.log(utils.swaggerInlineExample(utils.guessLanguage()));
16
-
17
- console.log('');
18
- console.log(`${chalk.blue('Parameter shorthand:')} Since parameters can be very verbose, we have a shorthand`);
19
- console.log('syntax for describing them.');
20
-
21
- console.log('');
22
- console.log(chalk.grey(' - (in) name=default* {type:format} description'));
23
- console.log('');
24
-
25
- console.log('This will be expanded when the OpenAPI definition is compiled.');
26
-
27
- console.log('');
28
- console.log(`For more information on this syntax, see ${chalk.yellow('https://github.com/readmeio/swagger-inline')}`);
29
-
30
- process.exit();
31
- };
@@ -1,14 +0,0 @@
1
- const cardinal = require('cardinal');
2
-
3
- exports.swagger = true;
4
- exports.desc = 'Output your OpenAPI definition (use --pretty for colors)';
5
-
6
- exports.run = function (info) {
7
- if (info.opts.pretty || info.opts.p) {
8
- console.log(cardinal.highlight(JSON.stringify(info.swagger, undefined, 2)));
9
- } else {
10
- console.log(JSON.stringify(info.swagger, undefined, 2));
11
- }
12
-
13
- process.exit();
14
- };
@@ -1,59 +0,0 @@
1
- const path = require('path');
2
-
3
- const chalk = require('chalk');
4
- const glob = require('glob');
5
-
6
- exports.swagger = false;
7
- exports.desc = 'Learn what you can do with oas';
8
- exports.weight = 2;
9
-
10
- function pad(text) {
11
- return `${text} `.substr(0, 23);
12
- }
13
-
14
- exports.run = function () {
15
- console.log('');
16
- console.log('Usage: oas <command>');
17
- console.log('');
18
-
19
- const files = glob.sync(path.join(__dirname, '*'));
20
- const commands = [];
21
-
22
- files.forEach(function (file) {
23
- const action = file.match(/(\w+).js/)[1];
24
-
25
- // eslint-disable-next-line import/no-dynamic-require, global-require
26
- const cmd = require(file);
27
- const desc = cmd.desc || '';
28
-
29
- let cmdUsage;
30
- if (cmd.swagger) {
31
- cmdUsage = `${pad(`${action} [oas.json]`)} ${chalk.grey(desc)}`;
32
- cmdUsage = cmdUsage.replace(/\[oas\.json\]/, chalk.grey('[oas.json]'));
33
- } else {
34
- cmdUsage = `${pad(action)} ${chalk.grey(desc)}`;
35
- }
36
-
37
- commands.push({
38
- msg: ` ${chalk.grey('$')} oas ${cmdUsage}`,
39
- weight: cmd.weight || 100,
40
- });
41
- });
42
-
43
- commands.sort((a, b) => {
44
- if (a.weight > b.weight) return 1;
45
- return b.weight > a.weight ? -1 : 0;
46
- });
47
-
48
- commands.forEach(function (command) {
49
- console.log(command.msg);
50
- });
51
-
52
- console.log('');
53
- console.log(
54
- `${chalk.green('Just getting started?')} Run ${chalk.yellow('oas init')} to create your OpenAPI definition.`
55
- );
56
- console.log('');
57
-
58
- process.exit();
59
- };
@@ -1,135 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
-
4
- const chalk = require('chalk');
5
- const inquirer = require('inquirer');
6
- const YAML = require('json2yaml');
7
-
8
- const utils = require('../lib/utils');
9
-
10
- exports.swagger = false;
11
- exports.desc = 'Create a new OpenAPI definition';
12
- exports.weight = 1;
13
-
14
- function writeFile(output, swagger) {
15
- let body = JSON.stringify(swagger, undefined, 2);
16
- if (output.match(/.(yaml|yml)/)) {
17
- body = YAML.stringify(swagger);
18
- body = body.replace(/^\s\s/gm, '').replace(/^---\n/, '');
19
- }
20
- fs.writeFileSync(output, body);
21
- }
22
-
23
- exports.run = function () {
24
- console.log(`This will help you set up an ${chalk.cyan('OpenAPI 3.0 Definition')} in your codebase, so`);
25
- console.log('you can start documenting your API!');
26
- console.log('');
27
-
28
- let pkg = {};
29
- if (fs.existsSync('./package.json')) {
30
- // eslint-disable-next-line import/no-dynamic-require, global-require
31
- pkg = require(path.join(process.cwd(), '/package.json'));
32
- }
33
-
34
- const questions = [
35
- {
36
- type: 'input',
37
- name: 'info.title',
38
- message: 'Name of the API',
39
- default: pkg.name || process.cwd().split('/').slice(-1)[0],
40
- },
41
- {
42
- type: 'input',
43
- name: 'info.version',
44
- message: 'Version number',
45
- default: pkg.version || '1.0.0',
46
- },
47
- {
48
- type: 'input',
49
- name: 'info.license',
50
- message: 'License',
51
- default: pkg.license,
52
- },
53
- {
54
- type: 'input',
55
- name: 'url',
56
- message: 'Full Base URL',
57
- validate(value) {
58
- const pass = /^(http|https|ws|wss):\/\/[^ "]+$/.test(value);
59
- if (pass) {
60
- return true;
61
- }
62
-
63
- return 'Please enter a valid URL, including the protocol.';
64
- },
65
- },
66
- {
67
- type: 'input',
68
- name: 'output',
69
- message: 'Output JSON or YAML file',
70
- validate(value) {
71
- const pass = /.(json|yaml|yml)$/.test(value);
72
- const doesntExist = !utils.fileExists(value);
73
-
74
- if (pass && doesntExist) {
75
- return true;
76
- }
77
-
78
- if (!pass) {
79
- return 'Your file must end with .json or .yaml';
80
- }
81
-
82
- return 'This file already exists';
83
- },
84
- },
85
- ];
86
-
87
- inquirer.prompt(questions).then(function (answers) {
88
- const swagger = {
89
- openapi: '3.0.0',
90
- info: {
91
- version: answers.info.version,
92
- title: answers.info.title,
93
- },
94
- servers: [
95
- {
96
- url: answers.url,
97
- },
98
- ],
99
- paths: {},
100
- };
101
-
102
- if (answers.info.license) {
103
- swagger.info.license = {
104
- name: answers.info.license,
105
- };
106
- }
107
-
108
- writeFile(answers.output, swagger);
109
-
110
- console.log('');
111
- console.log('======================');
112
- console.log('');
113
- console.log(chalk.green('SUCCESS!'));
114
- console.log('');
115
- console.log(`We've created your new OpenAPI file at ${chalk.yellow(answers.output)}.`);
116
- console.log('');
117
- console.log('You can document each endpoint right above the code. Just use the');
118
- console.log('following syntax in a comment above the code:');
119
- console.log('');
120
-
121
- console.log(utils.swaggerInlineExample(utils.guessLanguage()));
122
-
123
- console.log('');
124
- console.log('For more information on this syntax, see https://github.com/readmeio/swagger-inline');
125
- console.log('');
126
- console.log(`To see what you can do with your API, type ${chalk.yellow('oas help')}.`);
127
- console.log('');
128
- console.log(
129
- `To generate an OAS file, type ${chalk.yellow('oas generate')}. To publish it, type ${chalk.yellow('oas host')}!`
130
- );
131
- console.log('');
132
-
133
- process.exit();
134
- });
135
- };
@@ -1,9 +0,0 @@
1
- const chalk = require('chalk');
2
-
3
- exports.swagger = true;
4
- exports.desc = 'Validate your OpenAPI definition';
5
-
6
- exports.run = function () {
7
- console.log(`${chalk.green('✔ Success!')} Your OpenAPI definition is valid!`);
8
- process.exit();
9
- };
package/src/cli/index.js DELETED
@@ -1,46 +0,0 @@
1
- const path = require('path');
2
-
3
- const chalk = require('chalk');
4
-
5
- const utils = require('./lib/utils');
6
-
7
- function loadAction(action = 'help') {
8
- const file = path.join(__dirname, 'commands', `${action}.js`);
9
- if (utils.fileExists(file)) {
10
- // eslint-disable-next-line import/no-dynamic-require, global-require
11
- return require(file);
12
- }
13
-
14
- console.log(chalk.red('Action not found.'));
15
- console.log(`Type ${chalk.yellow('oas help')} to see all commands`);
16
- return process.exit(1);
17
- }
18
-
19
- module.exports = function (args, opts) {
20
- opts = opts || {};
21
-
22
- const cmd = loadAction(args[0]);
23
- if (!cmd) {
24
- return;
25
- }
26
-
27
- const info = {
28
- args,
29
- opts,
30
- };
31
-
32
- if (cmd.swagger) {
33
- utils.findSwagger(info, function (err, swagger) {
34
- if (err) {
35
- console.error(err);
36
- return;
37
- }
38
-
39
- info.swagger = swagger;
40
-
41
- cmd.run(info);
42
- });
43
- } else {
44
- cmd.run(info);
45
- }
46
- };
@@ -1,184 +0,0 @@
1
- const fs = require('fs');
2
-
3
- const cardinal = require('cardinal');
4
- const chalk = require('chalk');
5
- const glob = require('glob');
6
- const OASNormalize = require('oas-normalize').default;
7
- const swaggerInline = require('swagger-inline');
8
-
9
- exports.findSwagger = async function (info, cb) {
10
- const file = info.args[info.args.length - 1];
11
- const base = exports.isJSONOrYaml(file) ? file : undefined;
12
-
13
- if (!base) {
14
- console.error(
15
- `You must pass a base OpenAPI or Swagger definition into ${chalk.yellow('oas generate')} to build off of.`
16
- );
17
-
18
- console.error('');
19
- console.error('This base specification might look like the following:');
20
- console.error(
21
- cardinal.highlight(
22
- JSON.stringify(
23
- {
24
- openapi: '3.0.3',
25
- info: {
26
- title: 'Example OpenAPI base file for `oas`.',
27
- version: '1.0',
28
- },
29
- servers: [
30
- {
31
- url: 'https://api.example.com',
32
- },
33
- ],
34
- },
35
- null,
36
- 2
37
- )
38
- )
39
- );
40
-
41
- console.error('');
42
- console.error(
43
- `And supply that to ${chalk.yellow('oas generate')} as ${chalk.yellow('oas generate openapiBase.json')}`
44
- );
45
- process.exit(1);
46
- }
47
-
48
- let pathGlob = info.opts.pathGlob || '**/*';
49
- if (info.opts.path) {
50
- pathGlob = `${info.opts.path.replace(/\/$/, '')}/*`;
51
- }
52
-
53
- const generatedDefinition = await swaggerInline(pathGlob, {
54
- format: '.json',
55
- scope: info.opts.scope,
56
- base,
57
- pattern: info.opts.pattern || null,
58
- }).catch(err => {
59
- console.error(err);
60
- process.exit(1);
61
- });
62
-
63
- let oas = new OASNormalize(generatedDefinition);
64
- const bundledDefinition = await oas.bundle().catch(err => {
65
- console.error(err.message);
66
- process.exit(1);
67
- });
68
-
69
- oas = new OASNormalize(bundledDefinition, { colorizeErrors: true });
70
- await oas
71
- .validate()
72
- .then(schema => cb(undefined, schema))
73
- .catch(err => {
74
- if (info.opts.v) {
75
- console.log(cardinal.highlight(generatedDefinition));
76
- }
77
-
78
- console.log('');
79
- console.log(
80
- [
81
- chalk.red('Error validating the API definition!'),
82
- !info.opts.v ? `Run with ${chalk.grey('-v')} to see the invalid definition.` : '',
83
- ].join(' ')
84
- );
85
- console.log('');
86
-
87
- console.log(err.message);
88
- console.log('');
89
- process.exit(1);
90
- });
91
- };
92
-
93
- exports.isJSONOrYaml = function (file) {
94
- return Boolean(['.json', '.yaml', '.yml'].map(ext => file.endsWith(ext)).filter(Boolean).length);
95
- };
96
-
97
- exports.fileExists = function (file) {
98
- try {
99
- return fs.statSync(file).isFile();
100
- } catch (err) {
101
- return false;
102
- }
103
- };
104
-
105
- /**
106
- * Really simple way at guessing the language that their API might be written in. If we're wrong,
107
- * it's not a big deal!
108
- *
109
- * @returns {String}
110
- */
111
- exports.guessLanguage = function () {
112
- let language = 'js';
113
- let languages = {
114
- rb: 0,
115
- coffee: 0,
116
- py: 0,
117
- js: 0,
118
- java: 0,
119
- php: 0,
120
- go: 0,
121
- };
122
-
123
- const files = glob.sync('*');
124
- files.forEach(function (f) {
125
- const ext = f.split('.').slice(-1)[0];
126
- if (typeof languages[ext] !== 'undefined') {
127
- languages[ext] += 1;
128
- }
129
- });
130
-
131
- languages = Object.entries(languages).filter(lang => lang[1] > 0);
132
- if (languages.length > 0) {
133
- languages.sort(function (a, b) {
134
- if (a[1] > b[1]) return 1;
135
- return b[1] > a[1] ? -1 : 0;
136
- });
137
-
138
- languages.reverse();
139
-
140
- language = languages.shift()[0];
141
- }
142
-
143
- return language;
144
- };
145
-
146
- exports.swaggerInlineExample = function (lang) {
147
- const prefix = ' ';
148
-
149
- const annotation = [
150
- '@oas [get] /pet/{petId}',
151
- 'description: Returns all pets from the system that the user has access to',
152
- 'parameters:',
153
- ' - (path) petId=2* {Integer} The pet ID',
154
- ' - (query) limit {Integer:int32} The number of resources to return',
155
- ];
156
-
157
- const languages = {
158
- js: ['/*', ' * ', ' */', 'route.get("/pet/:petId", pet.show);'],
159
- jsx: ['/*', ' * ', ' */', 'route.get("/pet/:petId", pet.show);'],
160
- ts: ['/*', ' * ', ' */', 'route.get("/pet/:petId", pet.show);'],
161
- java: ['/*', ' * ', ' */', 'public String getPet(id) {'],
162
- php: ['/*', ' * ', ' */', 'function showPet($id) {'],
163
- coffee: ['###', '', '###', "route.get '/pet/:petId', pet.show"],
164
- rb: ['=begin', '', '=end', "get '/pet/:petId' do"],
165
- py: ['"""', '', '"""', 'def getPet(id):'],
166
- go: ['/*', ' * ', ' */', 'func getPet(id) {'],
167
- };
168
-
169
- lang = lang.toLowerCase();
170
- if (!lang || !languages[lang]) lang = 'javascript';
171
-
172
- const language = languages[lang];
173
-
174
- const out = [`${prefix}${chalk.cyan(language[0])}`];
175
-
176
- annotation.forEach(function (line) {
177
- out.push(`${prefix}${chalk.cyan(language[1])}${chalk.cyan(line)}`);
178
- });
179
-
180
- out.push(`${prefix}${chalk.cyan(language[2])}`);
181
- out.push(`${prefix}${chalk.grey(language[3])}`);
182
-
183
- return out.join('\n');
184
- };