openapi-jsonrpc-jsdoc 1.5.0 → 1.5.2

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 +80 -44
  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'};
@@ -164,30 +172,40 @@ export default async function openapiJsonrpcJsdoc({
164
172
  samples = ['node', 'javascript'],
165
173
  ...xHeaders
166
174
  }) {
167
- const allData = await jsdoc.explain({
168
- files: Array.isArray(files) ? files : [files],
169
- packageJson: packageUrl,
175
+ const options = {
170
176
  access,
171
177
  encoding,
178
+ samples,
179
+ files: Array.isArray(files) ? files : [files],
172
180
  undocumented: false,
173
181
  allowUnknownTags: true,
174
182
  dictionaries: ['jsdoc'],
175
- cache: true,
176
- samples,
177
- });
178
- const package_ = allData.find(item => item.kind === 'package');
179
- const documents = allData.filter(item => item.kind !== 'package');
183
+ };
184
+ if (info.title) {
185
+ options.cache = true;
186
+ } else {
187
+ options.package = packageUrl;
188
+ }
189
+ let documents;
190
+ if (options.cache) {
191
+ documents = await jsdoc.explain(options);
192
+ } else {
193
+ const allData = await jsdoc.explain(options);
194
+ documents = allData.filter(item => item.kind !== 'package');
195
+ const package_ = allData.find(item => item.kind === 'package');
196
+ info.version = package_.version;
197
+ info.title = package_.name;
198
+ info.description = package_.description;
199
+ }
200
+ if (!info.title) {
201
+ throw new Error('API title is required. Please set packageUrl or info object.');
202
+ }
180
203
  const temporaryDocument = {
181
204
  'openapi': openapi,
182
205
  'x-samples-enabled': samples.length > 0,
183
206
  'x-samples-languages': samples,
184
207
  ...xHeaders,
185
- 'info': {
186
- version: package_.version,
187
- title: package_.name,
188
- description: package_.description,
189
- ...info,
190
- },
208
+ 'info': info,
191
209
  'servers': servers,
192
210
  'paths': {},
193
211
  'components': {
@@ -218,9 +236,6 @@ export default async function openapiJsonrpcJsdoc({
218
236
  'security': Object.keys(securitySchemes).map(val => ({ [val]: [] })),
219
237
  'tags': [],
220
238
  };
221
- if (!temporaryDocument.info.title) {
222
- throw new Error('Info title is required');
223
- }
224
239
  const requiredSchema = ['method', 'jsonrpc'];
225
240
  prepare: for (const module of documents) {
226
241
  let isJsonRpc = false;
@@ -243,12 +258,11 @@ export default async function openapiJsonrpcJsdoc({
243
258
 
244
259
  const schema = {
245
260
  post: {
246
- operationId: filename,
261
+ operationId: apiName,
247
262
  deprecated: module.deprecated || false,
248
- summary: `/${apiName}`,
263
+ summary: module.summary ?? `/${apiName}`,
249
264
  description: module.description,
250
265
  tags: Array.from(tags),
251
- parameters: [],
252
266
  responses: {
253
267
  '200': {
254
268
  description: 'OK',
@@ -300,9 +314,12 @@ export default async function openapiJsonrpcJsdoc({
300
314
  },
301
315
  };
302
316
  if (module.params) {
303
- let exampleJSON = null;
317
+ const prevObject = {};
304
318
  if (module.examples?.length) {
305
- exampleJSON = JSON.parse(module.examples[0]);
319
+ const exampleJSON = JSON.parse(module.examples[0]);
320
+ if (exampleJSON) {
321
+ prevObject['default'] = exampleJSON;
322
+ }
306
323
  }
307
324
 
308
325
  const propertiesParameters = module.params.reduce(
@@ -313,15 +330,16 @@ export default async function openapiJsonrpcJsdoc({
313
330
  if (!parameter.type) {
314
331
  throw new Error('JSDoc parameter error: ' + apiName);
315
332
  }
316
- // todo поддержать не только object поле в аргументе функции
317
- if (parameter.type.names[0] === 'object') {
333
+ // если главный параметр объявлен как объект - пропускаем его
334
+ if (parameter.type.names.every(name => name.toLowerCase() === 'object')) {
318
335
  return accumulator;
319
336
  }
337
+ const isPlain = !parameter.name.includes('.');
320
338
 
321
339
  const name = extractName(parameter.name);
322
- accumulator.properties[name] = accumulator.properties[name] ?? {};
340
+ const prop = {};
323
341
  const description = parameter.description;
324
- const defaultValue = parameter.defaultvalue;
342
+ let defaultValue = parameter.defaultvalue;
325
343
 
326
344
  const {
327
345
  items,
@@ -332,45 +350,63 @@ export default async function openapiJsonrpcJsdoc({
332
350
  nullable,
333
351
  } = resolveSchemaFromTypeNames(parameter.type.names)
334
352
  if (!parameter.optional) {
353
+ if (!accumulator.required) {
354
+ accumulator.required = [];
355
+ }
335
356
  accumulator.required.push(name);
336
357
  }
337
358
  if (nullable) {
338
- accumulator.properties[name].nullable = nullable;
359
+ prop.nullable = nullable;
339
360
  }
340
- if (defaultValue) {
341
- accumulator.properties[name].default = defaultValue;
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);
342
367
  }
343
368
  if (constant) {
344
- accumulator.properties[name].const = constant;
369
+ prop.const = constant;
345
370
  }
346
371
  if (format) {
347
- accumulator.properties[name].format = format;
372
+ prop.format = format;
348
373
  }
349
374
  if (enumData) {
350
- accumulator.properties[name].enum = enumData;
375
+ prop.enum = enumData;
351
376
  }
352
377
  if (type) {
353
- accumulator.properties[name].type = type;
378
+ prop.type = type;
354
379
  }
355
380
  if (description) {
356
- accumulator.properties[name].description = description;
381
+ prop.description = description;
357
382
  }
358
383
  if (items) {
359
- accumulator.properties[name].items = items;
384
+ prop.items = items;
360
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
+ };
394
+ }
395
+
361
396
  return accumulator;
362
397
  },
363
- {
364
- title: 'Parameters',
365
- type: 'object',
366
- 'default': exampleJSON,
367
- required: [],
368
- properties: {},
369
- },
398
+ prevObject,
370
399
  );
371
- if (exampleJSON !== null) {
400
+ if (Object.keys(propertiesParameters).length) {
372
401
  const schemaPostJsdoc = schema.post.requestBody.content['application/json'].schema;
373
- schemaPostJsdoc.properties.params = propertiesParameters;
402
+ if (propertiesParameters.properties) {
403
+ schemaPostJsdoc.properties.params = {
404
+ type: 'object',
405
+ ...propertiesParameters,
406
+ };
407
+ } else {
408
+ schemaPostJsdoc.properties.params = propertiesParameters;
409
+ }
374
410
  }
375
411
  }
376
412
  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.0",
3
+ "version": "1.5.2",
4
4
  "description": "Transform JSDoc-annotated JSON-RPC 2.0 methods into OpenAPI specifications.",
5
5
  "main": "index.mjs",
6
6
  "type": "module",