openapi-jsonrpc-jsdoc 1.5.1 → 1.5.3

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 (2) hide show
  1. package/index.mjs +136 -76
  2. package/package.json +1 -1
package/index.mjs CHANGED
@@ -43,6 +43,14 @@ function resolveSchemaFromTypeNames(names) {
43
43
  items = {type: 'string'};
44
44
  break;
45
45
  }
46
+ case 'Array.<bigint>': {
47
+ type = 'array';
48
+ items = {
49
+ type: 'integer',
50
+ format: 'int64',
51
+ };
52
+ break;
53
+ }
46
54
  case 'Array.<number>': {
47
55
  type = 'array';
48
56
  items = {type: 'number'};
@@ -216,6 +224,16 @@ export default async function openapiJsonrpcJsdoc({
216
224
  },
217
225
  error: {
218
226
  type: 'object',
227
+ required: ['code', 'message'],
228
+ properties: {
229
+ code: {
230
+ type: 'integer',
231
+ default: -32001,
232
+ },
233
+ message: {
234
+ type: 'string',
235
+ },
236
+ },
219
237
  },
220
238
  jsonrpc: {
221
239
  type: 'string',
@@ -234,10 +252,10 @@ export default async function openapiJsonrpcJsdoc({
234
252
  const tags = new Set();
235
253
 
236
254
  if (module.tags && Array.isArray(module.tags)) {
237
- for (const {title, value} of module.tags) {
255
+ for (const {title, originalTitle, value} of module.tags) {
238
256
  if (title === 'json-rpc') {
239
257
  isJsonRpc = true;
240
- } else if (value && ['tags', 'tag'].includes(title)) {
258
+ } else if (value && ['tags', 'tag'].includes(originalTitle ?? title)) {
241
259
  value.split(',').map(t => t.trim()).forEach(t => tags.add(t));
242
260
  }
243
261
  }
@@ -248,27 +266,49 @@ export default async function openapiJsonrpcJsdoc({
248
266
  const {filename} = module.meta;
249
267
  const apiName = filename.replace(/\.js$/, '');
250
268
 
269
+ let resultValues;
270
+ switch (module.returns?.[0]?.description) {
271
+ case 'Promise<*>':
272
+ case 'Promise<object>': {
273
+ resultValues = 'object';
274
+ break;
275
+ }
276
+ default: {
277
+ resultValues = '';
278
+ break;
279
+ }
280
+ }
281
+
282
+ let description = module.description;
283
+ if (module.todo?.length) {
284
+ description += '\n\nTODO: ' + module.todo.join();
285
+ }
286
+
251
287
  const schema = {
252
288
  post: {
253
- operationId: filename,
289
+ operationId: apiName,
254
290
  deprecated: module.deprecated || false,
255
- summary: `/${apiName}`,
256
- description: module.description,
291
+ summary: module.summary ?? `/${apiName}`,
292
+ description: description,
257
293
  tags: Array.from(tags),
258
- parameters: [],
259
294
  responses: {
260
295
  '200': {
261
- description: 'OK',
296
+ description: 'OK response',
262
297
  content: {
263
298
  'application/json': {
264
299
  schema: {
265
300
  type: 'object',
301
+ properties: {
302
+ result: {
303
+ type: resultValues,
304
+ },
305
+ },
266
306
  },
267
307
  },
268
308
  },
269
309
  },
270
- default: {
271
- description: 'unexpected error',
310
+ '400': {
311
+ description: 'Unexpected error',
272
312
  content: {
273
313
  'application/json': {
274
314
  schema: {
@@ -288,16 +328,18 @@ export default async function openapiJsonrpcJsdoc({
288
328
  properties: {
289
329
  method: {
290
330
  type: 'string',
291
- description: `API method ${apiName}`,
331
+ 'default': apiName,
332
+ description: `API method header`,
292
333
  },
293
334
  id: {
294
335
  type: ['string', 'integer'],
295
- description: 'Request ID',
336
+ default: 'swagger_unique_indentifier',
337
+ description: 'Request ID header',
296
338
  },
297
339
  jsonrpc: {
298
340
  type: 'string',
299
341
  default: '2.0',
300
- description: 'JSON-RPC 2.0 protocol',
342
+ description: 'JSON-RPC 2.0 header',
301
343
  },
302
344
  },
303
345
  },
@@ -307,77 +349,95 @@ export default async function openapiJsonrpcJsdoc({
307
349
  },
308
350
  };
309
351
  if (module.params) {
310
- let exampleJSON = null;
352
+ const prevObject = {};
311
353
  if (module.examples?.length) {
312
- exampleJSON = JSON.parse(module.examples[0]);
354
+ const exampleJSON = JSON.parse(module.examples[0]);
355
+ if (exampleJSON) {
356
+ prevObject['default'] = exampleJSON;
357
+ }
313
358
  }
314
359
 
315
- const propertiesParameters = module.params.reduce(
316
- (accumulator, parameter) => {
317
- if (parameter.name.startsWith('_')) {
318
- return accumulator;
319
- }
320
- if (!parameter.type) {
321
- throw new Error('JSDoc parameter error: ' + apiName);
322
- }
323
- // todo поддержать не только object поле в аргументе функции
324
- if (parameter.type.names[0] === 'object') {
325
- return accumulator;
326
- }
360
+ let propertiesParameters = {};
361
+ let required = [];
362
+ for (const parameter of module.params) {
363
+ if (parameter.name.startsWith('_')) {
364
+ continue;
365
+ }
366
+ if (!parameter.type) {
367
+ throw new Error('JSDoc parameter error: ' + apiName);
368
+ }
369
+ // если главный параметр объявлен как объект - пропускаем его
370
+ if (parameter.type.names.every(name => name.toLowerCase() === 'object')) {
371
+ continue;
372
+ }
373
+ const isPlain = !parameter.name.includes('.');
327
374
 
328
- const name = extractName(parameter.name);
329
- accumulator.properties[name] = accumulator.properties[name] ?? {};
330
- const description = parameter.description;
331
- const defaultValue = parameter.defaultvalue;
375
+ const name = extractName(parameter.name);
376
+ const prop = {};
377
+ const description = parameter.description;
378
+ let defaultValue = parameter.defaultvalue;
332
379
 
333
- const {
334
- items,
335
- constant,
336
- enumData,
337
- type,
338
- format,
339
- nullable,
340
- } = resolveSchemaFromTypeNames(parameter.type.names)
341
- if (!parameter.optional) {
342
- accumulator.required.push(name);
343
- }
344
- if (nullable) {
345
- accumulator.properties[name].nullable = nullable;
346
- }
347
- if (defaultValue) {
348
- accumulator.properties[name].default = defaultValue;
349
- }
350
- if (constant) {
351
- accumulator.properties[name].const = constant;
352
- }
353
- if (format) {
354
- accumulator.properties[name].format = format;
355
- }
356
- if (enumData) {
357
- accumulator.properties[name].enum = enumData;
358
- }
359
- if (type) {
360
- accumulator.properties[name].type = type;
361
- }
362
- if (description) {
363
- accumulator.properties[name].description = description;
364
- }
365
- if (items) {
366
- accumulator.properties[name].items = items;
380
+ const {
381
+ items,
382
+ constant,
383
+ enumData,
384
+ type,
385
+ format,
386
+ nullable,
387
+ } = resolveSchemaFromTypeNames(parameter.type.names)
388
+ if (!parameter.optional) {
389
+ required.push(name);
390
+ }
391
+ if (nullable) {
392
+ prop.nullable = nullable;
393
+ }
394
+ if (defaultValue !== undefined) {
395
+ // fix for array type if it is not properly closed in JSDoc
396
+ if (typeof defaultValue === 'string' && defaultValue.startsWith('[') && !defaultValue.endsWith(']')) {
397
+ defaultValue += ']';
367
398
  }
368
- return accumulator;
369
- },
370
- {
371
- title: 'Parameters',
372
- type: 'object',
373
- 'default': exampleJSON,
374
- required: [],
375
- properties: {},
376
- },
377
- );
378
- if (exampleJSON !== null) {
399
+ prop.default = JSON.parse(defaultValue);
400
+ }
401
+ if (constant) {
402
+ prop.const = constant;
403
+ }
404
+ if (format) {
405
+ prop.format = format;
406
+ }
407
+ if (enumData) {
408
+ prop.enum = enumData;
409
+ }
410
+ if (type) {
411
+ prop.type = type;
412
+ }
413
+ if (description) {
414
+ prop.description = description;
415
+ }
416
+ if (items) {
417
+ prop.items = items;
418
+ }
419
+ if (isPlain) {
420
+ propertiesParameters = Object.assign(propertiesParameters, prop);
421
+ } else if (propertiesParameters.properties) {
422
+ propertiesParameters.properties[name] = prop;
423
+ } else {
424
+ propertiesParameters.properties = {
425
+ [name]: prop,
426
+ };
427
+ }
428
+ }
429
+ propertiesParameters.required = required;
430
+
431
+ if (Object.keys(propertiesParameters).length) {
379
432
  const schemaPostJsdoc = schema.post.requestBody.content['application/json'].schema;
380
- schemaPostJsdoc.properties.params = propertiesParameters;
433
+ if (propertiesParameters.properties) {
434
+ schemaPostJsdoc.properties.params = {
435
+ type: 'object',
436
+ ...propertiesParameters,
437
+ };
438
+ } else {
439
+ schemaPostJsdoc.properties.params = propertiesParameters;
440
+ }
381
441
  }
382
442
  }
383
443
  temporaryDocument.paths[`${api}${apiName}`] = schema;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openapi-jsonrpc-jsdoc",
3
- "version": "1.5.1",
3
+ "version": "1.5.3",
4
4
  "description": "Transform JSDoc-annotated JSON-RPC 2.0 methods into OpenAPI specifications.",
5
5
  "main": "index.mjs",
6
6
  "type": "module",