openapi-jsonrpc-jsdoc 1.5.2 → 1.5.4

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