@team-supercharge/oasg 13.2.0-feature-csharp-functions-1ae9e5ab.0 → 13.2.0-feature-csharp-functions-22a33fb4.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/bin/exec.js +12 -2
  2. package/bin/oasg +152 -119
  3. package/package.json +1 -1
package/bin/exec.js CHANGED
@@ -1,7 +1,7 @@
1
1
  const { exit } = require('process');
2
2
  const { execSync } = require('child_process');
3
3
 
4
- function exec(command, stdio) {
4
+ function execCommand(command, stdio) {
5
5
  try {
6
6
  execSync(`bash -e -c "${command}"`, { stdio: stdio || 'inherit' });
7
7
  } catch (e) {
@@ -10,4 +10,14 @@ function exec(command, stdio) {
10
10
  }
11
11
  }
12
12
 
13
- exports.exec = exec;
13
+ function execScript(script, stdio) {
14
+ try {
15
+ execSync(`bash -e ${script}`, { stdio: stdio || 'inherit' });
16
+ } catch (e) {
17
+ console.error(e.message);
18
+ exit(1);
19
+ }
20
+ }
21
+
22
+ exports.exec = execCommand;
23
+ exports.execScript = execScript;
package/bin/oasg CHANGED
@@ -3,7 +3,7 @@
3
3
  const fs = require('fs');
4
4
  const crypto = require('crypto');
5
5
  const ajv = new (require('ajv'))({
6
- strict: 'log'
6
+ strict: 'log',
7
7
  });
8
8
  const YAML = require('yamljs');
9
9
  const refParser = require('@apidevtools/json-schema-ref-parser');
@@ -15,6 +15,7 @@ const expressHttpProxy = require('express-http-proxy');
15
15
  const { exit } = require('process');
16
16
 
17
17
  const { exec } = require(`${__dirname}/exec.js`);
18
+ const { execScript } = require(`${__dirname}/exec.js`);
18
19
  const { merge } = require(`${__dirname}/merger.js`);
19
20
  const { applyOverrides } = require(`${__dirname}/overrider.js`);
20
21
  const { openApiTarget } = require(`${__dirname}/openapi-target.js`);
@@ -33,23 +34,23 @@ const PROXY_PORT = '9999';
33
34
 
34
35
  const DEFAULT_GENERATOR_MAPPING = {
35
36
  // client targets
36
- "android": { version: '7.0.1', generator: 'kotlin' },
37
- "angular": { version: '7.0.1', generator: 'typescript-angular' },
38
- "feign": { version: '7.0.1', generator: 'spring' },
39
- "feign-kotlin": { version: '7.0.1', generator: 'kotlin-spring' },
40
- "flutter": { version: '7.0.1', generator: 'dart-dio' },
41
- "ios": { version: '7.0.1', generator: 'swift5' },
42
- "python": { version: '7.0.1', generator: 'python' },
43
- "react": { version: '7.0.1', generator: 'typescript-fetch' },
37
+ android: { version: '7.0.1', generator: 'kotlin' },
38
+ angular: { version: '7.0.1', generator: 'typescript-angular' },
39
+ feign: { version: '7.0.1', generator: 'spring' },
40
+ 'feign-kotlin': { version: '7.0.1', generator: 'kotlin-spring' },
41
+ flutter: { version: '7.0.1', generator: 'dart-dio' },
42
+ ios: { version: '7.0.1', generator: 'swift5' },
43
+ python: { version: '7.0.1', generator: 'python' },
44
+ react: { version: '7.0.1', generator: 'typescript-fetch' },
44
45
  // server targets
45
- "nestjs": { version: '7.0.1', generator: 'typescript-angular' },
46
- "spring": { version: '7.0.1', generator: 'spring' },
47
- "spring-kotlin": { version: '7.0.1', generator: 'kotlin-spring' },
48
- "csharp-functions": { version: '7.0.1', generator: 'csharp-functions' },
46
+ nestjs: { version: '7.0.1', generator: 'typescript-angular' },
47
+ spring: { version: '7.0.1', generator: 'spring' },
48
+ 'spring-kotlin': { version: '7.0.1', generator: 'kotlin-spring' },
49
+ 'csharp-functions': { version: '7.0.1', generator: 'csharp-functions' },
49
50
  // misc targets
50
- "contract-testing": { version: '4.3.1', generator: 'typescript-node' },
51
- "openapi": { version: undefined, generator: undefined },
52
- "stubby": { version: '4.3.1', generator: 'stubby' },
51
+ 'contract-testing': { version: '4.3.1', generator: 'typescript-node' },
52
+ openapi: { version: undefined, generator: undefined },
53
+ stubby: { version: '4.3.1', generator: 'stubby' },
53
54
  };
54
55
  const DEFAULT_KTLINT_VERSION = '1.0.0';
55
56
  const BIN_FOLDER = 'out/.bin';
@@ -59,8 +60,8 @@ const CONFIG_FILE_NAME = 'config.json';
59
60
  const DEFAULT_SOURCE = {
60
61
  id: 'default',
61
62
  type: 'simple',
62
- input: 'api/openapi.yaml'
63
- }
63
+ input: 'api/openapi.yaml',
64
+ };
64
65
 
65
66
  let config;
66
67
 
@@ -76,71 +77,93 @@ async function run() {
76
77
  // handle command line
77
78
  require('yargs')
78
79
  // lint
79
- .command(['lint [source]', 'l'], 'lint definitions', (yargs) => {
80
- yargs
81
- .positional('source', {
80
+ .command(
81
+ ['lint [source]', 'l'],
82
+ 'lint definitions',
83
+ (yargs) => {
84
+ yargs.positional('source', {
82
85
  describe: 'specify a source (optional)',
83
- default: undefined
84
- })
85
- }, (argv) => lint(argv))
86
+ default: undefined,
87
+ });
88
+ },
89
+ (argv) => lint(argv)
90
+ )
86
91
 
87
92
  // serve
88
- .command(['serve [source]', 's'], 'serve definition', (yargs) => {
89
- yargs
90
- .positional('source', {
93
+ .command(
94
+ ['serve [source]', 's'],
95
+ 'serve definition',
96
+ (yargs) => {
97
+ yargs.positional('source', {
91
98
  describe: 'specify a source',
92
- default: 'default'
93
- })
94
- }, (argv) => serve(argv))
99
+ default: 'default',
100
+ });
101
+ },
102
+ (argv) => serve(argv)
103
+ )
95
104
 
96
105
  // proxy
97
- .command(['proxy [source]', 'p'], 'serve definition', (yargs) => {
98
- yargs
99
- .positional('source', {
100
- describe: 'specify a source',
101
- default: 'default'
102
- })
103
- .option('server', {
104
- describe: 'specify a server (from "servers" array)',
105
- alias: 's',
106
- demandOption: true
107
- })
108
- }, (argv) => proxy(argv))
106
+ .command(
107
+ ['proxy [source]', 'p'],
108
+ 'serve definition',
109
+ (yargs) => {
110
+ yargs
111
+ .positional('source', {
112
+ describe: 'specify a source',
113
+ default: 'default',
114
+ })
115
+ .option('server', {
116
+ describe: 'specify a server (from "servers" array)',
117
+ alias: 's',
118
+ demandOption: true,
119
+ });
120
+ },
121
+ (argv) => proxy(argv)
122
+ )
109
123
 
110
124
  // generate
111
- .command(['generate [target]', 'g'], 'generate packages', (yargs) => {
112
- yargs
113
- .positional('target', {
114
- describe: 'specify a target (optional)',
115
- default: undefined
116
- })
117
- .option('artifactVersion', {
118
- describe: 'Specify an artifactVersion (optional). \nIf you do not specify it, the tool uses the root package.json\'s version field.',
119
- default: undefined
120
- })
121
- .option('preRelease', {
122
- describe: 'Generate as pre-release (optional). \nHow a pre-release is handled varies between different target types.',
123
- type: 'boolean'
124
- })
125
- }, (argv) => generate(argv))
125
+ .command(
126
+ ['generate [target]', 'g'],
127
+ 'generate packages',
128
+ (yargs) => {
129
+ yargs
130
+ .positional('target', {
131
+ describe: 'specify a target (optional)',
132
+ default: undefined,
133
+ })
134
+ .option('artifactVersion', {
135
+ describe: "Specify an artifactVersion (optional). \nIf you do not specify it, the tool uses the root package.json's version field.",
136
+ default: undefined,
137
+ })
138
+ .option('preRelease', {
139
+ describe: 'Generate as pre-release (optional). \nHow a pre-release is handled varies between different target types.',
140
+ type: 'boolean',
141
+ });
142
+ },
143
+ (argv) => generate(argv)
144
+ )
126
145
 
127
146
  // publish
128
- .command(['publish [target]', 'p'], 'publish packages', (yargs) => {
129
- yargs
130
- .positional('target', {
131
- describe: 'specifiy a target (optional)',
132
- default: undefined
133
- })
134
- .option('preRelease', {
135
- describe: 'Publish as pre-release (optional). \nHow a pre-release is handled varies between different target types.',
136
- type: 'boolean'
137
- })
138
- }, (argv) => publish(argv))
147
+ .command(
148
+ ['publish [target]', 'p'],
149
+ 'publish packages',
150
+ (yargs) => {
151
+ yargs
152
+ .positional('target', {
153
+ describe: 'specifiy a target (optional)',
154
+ default: undefined,
155
+ })
156
+ .option('preRelease', {
157
+ describe: 'Publish as pre-release (optional). \nHow a pre-release is handled varies between different target types.',
158
+ type: 'boolean',
159
+ });
160
+ },
161
+ (argv) => publish(argv)
162
+ )
139
163
 
140
164
  // options
141
165
  .demandCommand(1, 'You need to specify a command!')
142
- .strict()
143
- .argv
166
+ .strict().argv;
144
167
  }
145
168
 
146
169
  function checkVersionMismatch() {
@@ -160,7 +183,7 @@ function checkVersionMismatch() {
160
183
  function checkRequiredCommands() {
161
184
  const missing = [];
162
185
 
163
- REQUIRED_COMMANDS.forEach(command => {
186
+ REQUIRED_COMMANDS.forEach((command) => {
164
187
  if (!commandExistsSync(command)) {
165
188
  missing.push(command);
166
189
  }
@@ -191,10 +214,10 @@ async function parseConfig() {
191
214
  }
192
215
 
193
216
  // validate config schema
194
- let schema = YAML.load(`${__dirname}/../config.schema.yml`)
217
+ let schema = YAML.load(`${__dirname}/../config.schema.yml`);
195
218
  schema = await refParser.dereference(schema);
196
219
  schema = mergeAllOf(schema, { ignoreAdditionalProperties: true });
197
- ajv.addVocabulary(["sources", "targets"]);
220
+ ajv.addVocabulary(['sources', 'targets']);
198
221
  const valid = ajv.validate(schema, config);
199
222
 
200
223
  if (!valid) {
@@ -208,7 +231,7 @@ async function parseConfig() {
208
231
  }
209
232
 
210
233
  // set default source values
211
- config.sources.forEach(s => {
234
+ config.sources.forEach((s) => {
212
235
  if (s.bundle === undefined) {
213
236
  s.bundle = true;
214
237
  }
@@ -227,14 +250,14 @@ async function parseConfig() {
227
250
  });
228
251
 
229
252
  // set default source to targets with undefined
230
- config.targets.forEach(t => {
253
+ config.targets.forEach((t) => {
231
254
  if (!t.source) {
232
255
  t.source = 'default';
233
256
  }
234
257
  });
235
258
 
236
259
  // set default generator values to targets with undefined
237
- config.targets.forEach(t => {
260
+ config.targets.forEach((t) => {
238
261
  if (!t.generator) {
239
262
  t.generator = DEFAULT_GENERATOR_MAPPING[t.type].version;
240
263
  }
@@ -246,20 +269,20 @@ async function parseConfig() {
246
269
  exit(1);
247
270
  }
248
271
  }
249
- })
272
+ });
250
273
 
251
274
  // set default ktlint to android targets with undefined
252
- config.targets.forEach(t => {
275
+ config.targets.forEach((t) => {
253
276
  //TODO: handle different types of platform
254
277
  if (t.type === 'android') {
255
278
  if (!t.formatter) {
256
279
  t.formatter = DEFAULT_KTLINT_VERSION;
257
280
  }
258
281
  }
259
- })
282
+ });
260
283
 
261
284
  // validate uniqueness of source IDs
262
- const sourceIds = config.sources.map(s => s.id);
285
+ const sourceIds = config.sources.map((s) => s.id);
263
286
  const duplicateSourceIds = findDuplicates(sourceIds);
264
287
 
265
288
  if (duplicateSourceIds.length > 0) {
@@ -268,7 +291,7 @@ async function parseConfig() {
268
291
  }
269
292
 
270
293
  // validate uniqueness of target IDs
271
- const targetIds = config.targets.map(t => t.id);
294
+ const targetIds = config.targets.map((t) => t.id);
272
295
  const duplicateTargetIds = findDuplicates(targetIds);
273
296
 
274
297
  if (duplicateTargetIds.length > 0) {
@@ -277,7 +300,7 @@ async function parseConfig() {
277
300
  }
278
301
 
279
302
  // validate targets have valid sources
280
- config.targets.forEach(t => {
303
+ config.targets.forEach((t) => {
281
304
  if (!sourceIds.includes(t.source)) {
282
305
  console.error(`source: ${t.source} not found for target: ${t.id}`);
283
306
  exit(1);
@@ -285,8 +308,8 @@ async function parseConfig() {
285
308
  });
286
309
 
287
310
  // validate unused sources
288
- const usedSources = config.targets.map(t => t.source);
289
- config.sources.forEach(s => {
311
+ const usedSources = config.targets.map((t) => t.source);
312
+ config.sources.forEach((s) => {
290
313
  if (!usedSources.includes(s.id)) {
291
314
  console.error(`source: ${s.id} is not used in any of the targets`);
292
315
  exit(1);
@@ -294,7 +317,7 @@ async function parseConfig() {
294
317
  });
295
318
 
296
319
  // validate source inputs exists
297
- config.sources.forEach(s => {
320
+ config.sources.forEach((s) => {
298
321
  switch (s.type) {
299
322
  case 'simple':
300
323
  if (!fs.existsSync(s.input)) {
@@ -305,12 +328,12 @@ async function parseConfig() {
305
328
  break;
306
329
 
307
330
  case 'merged':
308
- s.inputs.forEach(i => {
331
+ s.inputs.forEach((i) => {
309
332
  if (fs.existsSync(i)) {
310
333
  return;
311
334
  }
312
335
  const matches = globSync(i);
313
- if (matches.every(m => fs.existsSync(m))) {
336
+ if (matches.every((m) => fs.existsSync(m))) {
314
337
  return;
315
338
  }
316
339
  console.error(`input file: ${i} not found for source: ${s.id}`);
@@ -335,7 +358,11 @@ async function buildSources(sourceIds) {
335
358
  continue;
336
359
  }
337
360
 
338
- console.log(`\n=====\n id:\t\t${source.id}\n type:\t\t${source.type}\n bundle:\t${source.bundle}\n sortSchemas:\t${source.sortSchemas}\n decorators: \t${JSON.stringify(source.decorators)}\n cleanup:\t${source.cleanup}\n---\n`);
361
+ console.log(
362
+ `\n=====\n id:\t\t${source.id}\n type:\t\t${source.type}\n bundle:\t${source.bundle}\n sortSchemas:\t${
363
+ source.sortSchemas
364
+ }\n decorators: \t${JSON.stringify(source.decorators)}\n cleanup:\t${source.cleanup}\n---\n`
365
+ );
339
366
 
340
367
  let file;
341
368
 
@@ -366,8 +393,8 @@ async function lint(argv) {
366
393
 
367
394
  // gather and deduplicate input files
368
395
  let inputs = [];
369
- sourceIds.forEach(sourceId => {
370
- const source = config.sources.find(s => s.id === sourceId);
396
+ sourceIds.forEach((sourceId) => {
397
+ const source = config.sources.find((s) => s.id === sourceId);
371
398
 
372
399
  switch (source.type) {
373
400
  case 'simple':
@@ -375,9 +402,9 @@ async function lint(argv) {
375
402
  break;
376
403
 
377
404
  case 'merged':
378
- source.inputs.forEach(i => inputs.push(i));
405
+ source.inputs.forEach((i) => inputs.push(i));
379
406
  }
380
- })
407
+ });
381
408
  inputs = Array.from(new Set(inputs));
382
409
 
383
410
  exec(`npx spectral lint --fail-severity warn ${inputs.join(' ')}`);
@@ -395,16 +422,16 @@ async function serve(argv) {
395
422
  const app = express();
396
423
 
397
424
  // configure proxying
398
- const proxyHost = function(request) {
425
+ const proxyHost = function (request) {
399
426
  const url = new URL(request.query.u);
400
427
  return url.origin;
401
428
  };
402
429
 
403
430
  const proxyOptions = {
404
- proxyReqPathResolver: function(request) {
431
+ proxyReqPathResolver: function (request) {
405
432
  const url = new URL(request.query.u);
406
433
  return `${url.pathname}${url.search}${url.hash}`;
407
- }
434
+ },
408
435
  };
409
436
  app.use('/proxy', expressHttpProxy(proxyHost, proxyOptions));
410
437
 
@@ -412,15 +439,15 @@ async function serve(argv) {
412
439
  var swaggerOptions = {
413
440
  swaggerOptions: {
414
441
  showMutatedRequest: false,
415
- requestInterceptor: function(request) {
442
+ requestInterceptor: function (request) {
416
443
  if (request.url.startsWith('http://localhost')) {
417
444
  return request;
418
445
  }
419
446
 
420
447
  request.url = '/proxy?u=' + encodeURIComponent(request.url);
421
448
  return request;
422
- }
423
- }
449
+ },
450
+ },
424
451
  };
425
452
  app.use('/', swaggerUi.serve, swaggerUi.setup(document, swaggerOptions));
426
453
 
@@ -440,7 +467,7 @@ async function proxy(argv) {
440
467
  const document = YAML.load(input);
441
468
 
442
469
  // validate server name
443
- const validServerNames = document.servers.map(s => s.description);
470
+ const validServerNames = document.servers.map((s) => s.description);
444
471
  const serverName = argv.server;
445
472
 
446
473
  if (!validServerNames.includes(serverName)) {
@@ -449,7 +476,7 @@ async function proxy(argv) {
449
476
  }
450
477
 
451
478
  // validate server url
452
- const server = document.servers.find(s => s.description === serverName);
479
+ const server = document.servers.find((s) => s.description === serverName);
453
480
  if (!server.url) {
454
481
  console.error(`url must be defined for server ${server.description}`);
455
482
  exit(1);
@@ -470,8 +497,8 @@ async function generate(argv) {
470
497
 
471
498
  console.log(`generate targets: ${targetIds}`);
472
499
 
473
- targetIds.forEach(targetId => {
474
- const target = config.targets.find(t => t.id === targetId);
500
+ targetIds.forEach((targetId) => {
501
+ const target = config.targets.find((t) => t.id === targetId);
475
502
 
476
503
  // handle docs target
477
504
  if (target.type === 'openapi') {
@@ -491,7 +518,11 @@ async function generate(argv) {
491
518
  const templateDir = customizeTemplates(target);
492
519
 
493
520
  // run generation
494
- exec(`bash -e ${__dirname}/../targets/${target.type}/generate.sh ${VERSION} ${binary} ${CONFIG_FILE_NAME} ${target.id} ${sources[target.source]} ${formatter} ${target.generatorId} ${preRelease.toString()} ${templateDir}`);
521
+ execScript(
522
+ `${__dirname}/../targets/${target.type}/generate.sh ${VERSION} ${binary} ${CONFIG_FILE_NAME} ${target.id} ${
523
+ sources[target.source]
524
+ } ${formatter} ${target.generatorId} ${preRelease.toString()} ${templateDir}`
525
+ );
495
526
  });
496
527
  }
497
528
 
@@ -503,8 +534,8 @@ async function publish(argv) {
503
534
 
504
535
  console.log(`publish targets: ${targetIds}`);
505
536
 
506
- targetIds.forEach(targetId => {
507
- const target = config.targets.find(t => t.id === targetId);
537
+ targetIds.forEach((targetId) => {
538
+ const target = config.targets.find((t) => t.id === targetId);
508
539
 
509
540
  // handle docs target
510
541
  if (target.type === 'openapi') {
@@ -520,13 +551,17 @@ async function publish(argv) {
520
551
  formatter = fetchFormatter(target);
521
552
  }
522
553
 
523
- exec(`bash -e ${__dirname}/../targets/${target.type}/publish.sh ${VERSION} ${binary} ${CONFIG_FILE_NAME} ${target.id} ${sources[target.source]} ${formatter} ${target.generatorId} ${preRelease.toString()}`);
554
+ execScript(
555
+ `${__dirname}/../targets/${target.type}/publish.sh ${VERSION} ${binary} ${CONFIG_FILE_NAME} ${target.id} ${
556
+ sources[target.source]
557
+ } ${formatter} ${target.generatorId} ${preRelease.toString()}`
558
+ );
524
559
  });
525
560
  }
526
561
 
527
562
  function fetchBinary(target) {
528
563
  // determine binary
529
- const generator = target.generator
564
+ const generator = target.generator;
530
565
  const binary = {};
531
566
 
532
567
  if (generator.startsWith('http')) {
@@ -534,8 +569,7 @@ function fetchBinary(target) {
534
569
 
535
570
  const hash = crypto.createHash('sha256').update(binary.url).digest('hex').substring(0, 8);
536
571
  binary.name = `openapi-generator-cli-${hash}.jar`;
537
- }
538
- else {
572
+ } else {
539
573
  binary.url = `https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/${generator}/openapi-generator-cli-${generator}.jar`;
540
574
  binary.name = `openapi-generator-cli-${generator}.jar`;
541
575
  }
@@ -557,18 +591,16 @@ function fetchBinary(target) {
557
591
 
558
592
  function fetchFormatter(target) {
559
593
  // determine binary
560
- const formatter = target.formatter
594
+ const formatter = target.formatter;
561
595
  const binary = {};
562
596
 
563
-
564
597
  //TODO: handle different types of platforms
565
598
  if (formatter.startsWith('http')) {
566
599
  binary.url = formatter;
567
600
 
568
601
  const hash = crypto.createHash('sha256').update(binary.url).digest('hex').substring(0, 8);
569
602
  binary.name = `ktlint-${hash}`;
570
- }
571
- else {
603
+ } else {
572
604
  binary.url = `https://github.com/pinterest/ktlint/releases/download/${formatter}/ktlint`;
573
605
  binary.name = `ktlint-${formatter}`;
574
606
  }
@@ -628,7 +660,7 @@ function determineSourceIds(argv) {
628
660
  }
629
661
 
630
662
  function validSourceIds() {
631
- return config.sources.map(s => s.id);
663
+ return config.sources.map((s) => s.id);
632
664
  }
633
665
 
634
666
  function checkSourceId(sourceId) {
@@ -652,8 +684,8 @@ function determineTargetIds(argv) {
652
684
 
653
685
  function sourceIdsFromTargetIds(targetIds) {
654
686
  const sourceIds = [];
655
- targetIds.forEach(targetId => {
656
- const target = config.targets.find(t => t.id === targetId);
687
+ targetIds.forEach((targetId) => {
688
+ const target = config.targets.find((t) => t.id === targetId);
657
689
  if (target.source) {
658
690
  sourceIds.push(target.source);
659
691
  }
@@ -662,7 +694,7 @@ function sourceIdsFromTargetIds(targetIds) {
662
694
  }
663
695
 
664
696
  function validTargetIds() {
665
- return config.targets.map(t => t.id);
697
+ return config.targets.map((t) => t.id);
666
698
  }
667
699
 
668
700
  function checkTargetId(targetId) {
@@ -674,8 +706,9 @@ function checkTargetId(targetId) {
674
706
 
675
707
  // find duplicates
676
708
  function findDuplicates(arr) {
677
- return arr.reduce(function(acc, el, i, arr) {
678
- if (arr.indexOf(el) !== i && acc.indexOf(el) < 0) acc.push(el); return acc;
709
+ return arr.reduce(function (acc, el, i, arr) {
710
+ if (arr.indexOf(el) !== i && acc.indexOf(el) < 0) acc.push(el);
711
+ return acc;
679
712
  }, []);
680
713
  }
681
714
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@team-supercharge/oasg",
3
- "version": "13.2.0-feature-csharp-functions-1ae9e5ab.0",
3
+ "version": "13.2.0-feature-csharp-functions-22a33fb4.0",
4
4
  "description": "Node-based tool to lint OpenAPI documents and generate clients, servers and documentation from them",
5
5
  "author": "Supercharge",
6
6
  "license": "MIT",