openapi-jsonrpc-jsdoc 1.4.3 → 1.5.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.
Files changed (3) hide show
  1. package/README.md +51 -95
  2. package/index.mjs +50 -19
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -17,15 +17,19 @@ npm i openapi-jsonrpc-jsdoc
17
17
  * @description Название API
18
18
  * @param {object} parameters - params
19
19
  * @param {string} parameters.id - id
20
+ * @param {string} [parameters.test] - test
21
+ * @param {string[]} parameters.array - array
22
+ * @param {1|2} parameters.num - enum
23
+ * @tags api
20
24
  * @example
21
25
  * {
22
- * "@context": "https://www.w3.org/ns/activitystreams",
23
- * "type": "Note"
26
+ * "id": "https://www.w3.org/ns/activitystreams"
24
27
  * }
25
28
  */
26
29
  module.exports = (parameters) => {
27
- return parameters.id;
28
- }
30
+ return parameters.id;
31
+ };
32
+
29
33
  ```
30
34
 
31
35
  ### Generate OpenAPI JSON
@@ -39,6 +43,9 @@ openapiJSONRpcJSDoc({
39
43
  url: '0.0.0.0:8080',
40
44
  },
41
45
  ],
46
+ info: {
47
+ title: 'Test API',
48
+ },
42
49
  packageUrl: './package.json',
43
50
  files: './api/*.js',
44
51
  }).then(data => {
@@ -51,22 +58,16 @@ openapiJSONRpcJSDoc({
51
58
 
52
59
  ```json
53
60
  {
54
- "x-send-defaults": true,
55
61
  "openapi": "3.1.0",
56
- "x-api-id": "json-rpc-example",
57
- "x-headers": [],
58
- "x-explorer-enabled": true,
59
- "x-proxy-enabled": true,
60
62
  "x-samples-enabled": true,
61
63
  "x-samples-languages": [
62
- "curl",
63
64
  "node",
64
65
  "javascript"
65
66
  ],
66
67
  "info": {
67
- "version": "1.0.4",
68
- "title": "openapi-jsonrpc-jsdoc",
69
- "description": "OpenAPI generator"
68
+ "version": "1.4.3",
69
+ "title": "Test API",
70
+ "description": "Transform JSDoc-annotated JSON-RPC 2.0 methods into OpenAPI specifications."
70
71
  },
71
72
  "servers": [
72
73
  {
@@ -81,7 +82,7 @@ openapiJSONRpcJSDoc({
81
82
  "summary": "/v1",
82
83
  "description": "Название API",
83
84
  "tags": [
84
- "JSONRPC"
85
+ "api"
85
86
  ],
86
87
  "parameters": [],
87
88
  "responses": {
@@ -107,32 +108,31 @@ openapiJSONRpcJSDoc({
107
108
  }
108
109
  },
109
110
  "requestBody": {
111
+ "required": true,
110
112
  "content": {
111
113
  "application/json": {
112
114
  "schema": {
113
115
  "type": "object",
114
116
  "required": [
115
117
  "method",
116
- "id",
117
- "jsonrpc",
118
- "params"
118
+ "jsonrpc"
119
119
  ],
120
120
  "properties": {
121
121
  "method": {
122
122
  "type": "string",
123
- "default": "v1",
124
123
  "description": "API method v1"
125
124
  },
126
125
  "id": {
127
- "type": "integer",
128
- "default": 1,
129
- "format": "int32",
126
+ "type": [
127
+ "string",
128
+ "integer"
129
+ ],
130
130
  "description": "Request ID"
131
131
  },
132
132
  "jsonrpc": {
133
133
  "type": "string",
134
134
  "default": "2.0",
135
- "description": "JSON-RPC Version (2.0)"
135
+ "description": "JSON-RPC 2.0 protocol"
136
136
  },
137
137
  "params": {
138
138
  "title": "Parameters",
@@ -142,15 +142,33 @@ openapiJSONRpcJSDoc({
142
142
  "type": "Note"
143
143
  },
144
144
  "required": [
145
- "method",
146
145
  "id",
147
- "jsonrpc",
148
- "id"
146
+ "array",
147
+ "num"
149
148
  ],
150
149
  "properties": {
151
150
  "id": {
152
151
  "type": "string",
153
152
  "description": "id"
153
+ },
154
+ "test": {
155
+ "type": "string",
156
+ "description": "test"
157
+ },
158
+ "array": {
159
+ "type": "array",
160
+ "description": "array",
161
+ "items": {
162
+ "type": "string"
163
+ }
164
+ },
165
+ "num": {
166
+ "enum": [
167
+ 1,
168
+ 2
169
+ ],
170
+ "type": "integer",
171
+ "description": "enum"
154
172
  }
155
173
  }
156
174
  }
@@ -160,83 +178,18 @@ openapiJSONRpcJSDoc({
160
178
  }
161
179
  }
162
180
  }
163
- },
164
- "/api/v2": {
165
- "post": {
166
- "operationId": "v2.js",
167
- "deprecated": true,
168
- "summary": "/v2",
169
- "description": "Название API 2",
170
- "tags": [
171
- "JSONRPC"
172
- ],
173
- "parameters": [],
174
- "responses": {
175
- "200": {
176
- "description": "OK",
177
- "content": {
178
- "application/json": {
179
- "schema": {
180
- "type": "object"
181
- }
182
- }
183
- }
184
- },
185
- "default": {
186
- "description": "unexpected error",
187
- "content": {
188
- "application/json": {
189
- "schema": {
190
- "$ref": "#/components/schemas/Error"
191
- }
192
- }
193
- }
194
- }
195
- },
196
- "requestBody": {
197
- "content": {
198
- "application/json": {
199
- "schema": {
200
- "type": "object",
201
- "required": [
202
- "method",
203
- "id",
204
- "jsonrpc"
205
- ],
206
- "properties": {
207
- "method": {
208
- "type": "string",
209
- "default": "v2",
210
- "description": "API method v2"
211
- },
212
- "id": {
213
- "type": "integer",
214
- "default": 1,
215
- "format": "int32",
216
- "description": "Request ID"
217
- },
218
- "jsonrpc": {
219
- "type": "string",
220
- "default": "2.0",
221
- "description": "JSON-RPC Version (2.0)"
222
- }
223
- }
224
- }
225
- }
226
- }
227
- }
228
- }
229
181
  }
230
182
  },
231
183
  "components": {
232
184
  "securitySchemes": {
233
185
  "BasicAuth": {
234
186
  "type": "http",
235
- "scheme": "digest"
187
+ "scheme": "basic"
236
188
  }
237
189
  },
238
190
  "schemas": {
239
191
  "Error": {
192
+ "type": "object",
240
193
  "required": [
241
194
  "error",
242
195
  "id",
@@ -244,14 +197,17 @@ openapiJSONRpcJSDoc({
244
197
  ],
245
198
  "properties": {
246
199
  "id": {
247
- "type": "integer",
248
- "format": "int32"
200
+ "type": [
201
+ "string",
202
+ "integer"
203
+ ]
249
204
  },
250
205
  "error": {
251
206
  "type": "object"
252
207
  },
253
208
  "jsonrpc": {
254
- "type": "string"
209
+ "type": "string",
210
+ "default": "2.0"
255
211
  }
256
212
  }
257
213
  }
package/index.mjs CHANGED
@@ -20,6 +20,15 @@ function extractTypeName(names = []) {
20
20
  return typeName;
21
21
  }
22
22
 
23
+ function isBigInt64(n) {
24
+ try {
25
+ const b = BigInt(n);
26
+ return b >= -9223372036854775808n && b <= 9223372036854775807n;
27
+ } catch {
28
+ return false;
29
+ }
30
+ }
31
+
23
32
  function resolveSchemaFromTypeNames(names) {
24
33
  let type;
25
34
  let format;
@@ -73,20 +82,29 @@ function resolveSchemaFromTypeNames(names) {
73
82
  enumData = enumData.map((n) => {
74
83
  if (!Number.isNaN(Number(n))) {
75
84
  return Number(n);
85
+ } else if (isBigInt64(n)) {
86
+ return n;
76
87
  }
77
- return n;
88
+ return String(n);
78
89
  });
79
90
 
80
- if (enumData.every(n => Number.isInteger(Number(n)))) {
91
+ if (enumData.every(n => Number.isSafeInteger(n))) {
92
+ type = 'integer';
93
+ } else if (enumData.every(n => Number.isInteger(n))) {
94
+ type = 'number';
95
+ format = 'float';
96
+ } else if (enumData.every(n => typeof n === 'number' && n === Math.fround(n))) {
97
+ type = 'number';
98
+ format = 'double';
99
+ } else if (enumData.every(n => isBigInt64(n))) {
81
100
  type = 'integer';
101
+ format = 'int64';
82
102
  } else if (enumData.every(n => !Number.isNaN(Number(n)))) {
83
103
  type = 'number';
84
104
  } else if (enumData.every(n => n?.toLowerCase() === 'boolean')) {
85
105
  type = 'boolean';
86
106
  } else if (enumData.every(n => n?.toLowerCase() === 'number')) {
87
107
  type = 'number';
88
- } else if (enumData.every(n => n?.toLowerCase() === 'string')) {
89
- type = 'string';
90
108
  } else if (enumData.every(n => n?.toLowerCase() === 'date')) {
91
109
  type = 'string';
92
110
  format = 'date-time';
@@ -99,8 +117,13 @@ function resolveSchemaFromTypeNames(names) {
99
117
  } else if (enumData.every(n => n?.toLowerCase() === 'false')) {
100
118
  type = 'boolean';
101
119
  constant = false;
102
- } else {
120
+ } else if (enumData.every(n => typeof n === 'string')) {
103
121
  type = 'string';
122
+ } else if (enumData.length === 1) {
123
+ type = enumData[0];
124
+ constant = true;
125
+ } else {
126
+ type = undefined;
104
127
  }
105
128
 
106
129
  if (enumData?.length === 1) {
@@ -108,6 +131,8 @@ function resolveSchemaFromTypeNames(names) {
108
131
  [format] = enumData;
109
132
  }
110
133
  enumData = undefined;
134
+ } else if (nullable) {
135
+ enumData.push(null);
111
136
  }
112
137
  break;
113
138
  }
@@ -128,37 +153,40 @@ function resolveSchemaFromTypeNames(names) {
128
153
 
129
154
  export default async function openapiJsonrpcJsdoc({
130
155
  openapi = '3.1.0',
156
+ encoding = 'utf8',
157
+ access = 'public',
131
158
  files,
159
+ info = {},
132
160
  securitySchemes = {},
133
161
  packageUrl,
134
162
  servers,
135
163
  api = '/',
164
+ samples = ['node', 'javascript'],
165
+ ...xHeaders
136
166
  }) {
137
167
  const allData = await jsdoc.explain({
138
168
  files: Array.isArray(files) ? files : [files],
139
- package: packageUrl,
140
- access: 'public',
141
- encoding: 'utf8',
169
+ packageJson: packageUrl,
170
+ access,
171
+ encoding,
142
172
  undocumented: false,
143
173
  allowUnknownTags: true,
144
174
  dictionaries: ['jsdoc'],
145
175
  cache: true,
176
+ samples,
146
177
  });
147
178
  const package_ = allData.find(item => item.kind === 'package');
148
179
  const documents = allData.filter(item => item.kind !== 'package');
149
180
  const temporaryDocument = {
150
181
  'openapi': openapi,
151
- 'x-send-defaults': true,
152
- 'x-api-id': 'json-rpc-example',
153
- 'x-headers': [],
154
- 'x-explorer-enabled': true,
155
- 'x-proxy-enabled': true,
156
- 'x-samples-enabled': true,
157
- 'x-samples-languages': ['node', 'javascript'],
182
+ 'x-samples-enabled': samples.length > 0,
183
+ 'x-samples-languages': samples,
184
+ ...xHeaders,
158
185
  'info': {
159
186
  version: package_.version,
160
187
  title: package_.name,
161
188
  description: package_.description,
189
+ ...info,
162
190
  },
163
191
  'servers': servers,
164
192
  'paths': {},
@@ -166,6 +194,7 @@ export default async function openapiJsonrpcJsdoc({
166
194
  securitySchemes,
167
195
  schemas: {
168
196
  Error: {
197
+ type: 'object',
169
198
  required: [
170
199
  'error',
171
200
  'id',
@@ -173,14 +202,14 @@ export default async function openapiJsonrpcJsdoc({
173
202
  ],
174
203
  properties: {
175
204
  id: {
176
- type: 'integer',
177
- format: 'int32',
205
+ type: ['string', 'integer'],
178
206
  },
179
207
  error: {
180
208
  type: 'object',
181
209
  },
182
210
  jsonrpc: {
183
211
  type: 'string',
212
+ default: '2.0',
184
213
  },
185
214
  },
186
215
  },
@@ -189,6 +218,9 @@ export default async function openapiJsonrpcJsdoc({
189
218
  'security': Object.keys(securitySchemes).map(val => ({ [val]: [] })),
190
219
  'tags': [],
191
220
  };
221
+ if (!temporaryDocument.info.title) {
222
+ throw new Error('Info title is required');
223
+ }
192
224
  const requiredSchema = ['method', 'jsonrpc'];
193
225
  prepare: for (const module of documents) {
194
226
  let isJsonRpc = false;
@@ -249,11 +281,10 @@ export default async function openapiJsonrpcJsdoc({
249
281
  properties: {
250
282
  method: {
251
283
  type: 'string',
252
- default: apiName,
253
284
  description: `API method ${apiName}`,
254
285
  },
255
286
  id: {
256
- type: ['string'],
287
+ type: ['string', 'integer'],
257
288
  description: 'Request ID',
258
289
  },
259
290
  jsonrpc: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openapi-jsonrpc-jsdoc",
3
- "version": "1.4.3",
3
+ "version": "1.5.0",
4
4
  "description": "Transform JSDoc-annotated JSON-RPC 2.0 methods into OpenAPI specifications.",
5
5
  "main": "index.mjs",
6
6
  "type": "module",