@trayio/tray-openapi 4.4.0 → 4.4.1

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.
@@ -80,7 +80,7 @@ class OpenApiSchemaImporter {
80
80
  }));
81
81
  }
82
82
  generateOperationFromPath(path, connectorPath, baseUrl, connectorName) {
83
- return (0, function_1.pipe)((0, Array_1.traverse)(TE.ApplicativeSeq)((route) => (0, function_1.pipe)(this.decodeOperation(route.path, path.path, route.method), TE.bindTo('decodedPath'), TE.chain(({ decodedPath }) => (0, function_1.pipe)(this.generateOperationDirectory(connectorPath, decodedPath.operationId), TE.bind('inputs', () => TE.fromEither((0, GenerateInputSchema_1.generateInputSchema)(decodedPath))), TE.bind('outputs', () => (0, GenerateOutput_1.generateOutputSchema)(decodedPath.responses)), TE.bind('decodedPath', () => TE.right(decodedPath)))), TE.chain(({ inputs, outputs, decodedPath }) => this.generateHandlerFilesAndOperationJson(route.method, decodedPath, `${connectorPath}/src/${(0, lodash_1.kebabCase)(decodedPath.operationId)}`, baseUrl, path.path, connectorName, inputs, outputs)), TE.map(() => ({
83
+ return (0, function_1.pipe)((0, Array_1.traverse)(TE.ApplicativeSeq)((route) => (0, function_1.pipe)(this.decodeOperation(route.path, path.path, route.method), TE.bindTo('decodedPath'), TE.chain(({ decodedPath }) => (0, function_1.pipe)(this.generateOperationDirectory(connectorPath, decodedPath.operationId), TE.bind('inputs', () => TE.fromEither((0, GenerateInputSchema_1.generateInputSchema)(decodedPath))), TE.bind('outputs', () => (0, GenerateOutput_1.generateOutputSchema)(decodedPath.responses)), TE.bind('decodedPath', () => TE.right(decodedPath)))), TE.chain(({ inputs, outputs, decodedPath }) => this.generateHandlerFilesAndOperationJson(route.method, decodedPath, `${connectorPath}/src/${(0, lodash_1.snakeCase)(decodedPath.operationId)}`, baseUrl, path.path, connectorName, inputs, outputs)), TE.map(() => ({
84
84
  tag: 'success',
85
85
  httpMethod: route.method,
86
86
  path: path.path,
@@ -127,7 +127,7 @@ class OpenApiSchemaImporter {
127
127
  })), TE.chain((handlerInput) => writeFile(handlerInput, 'handler.test.ts'))),
128
128
  generateOutputType: (0, function_1.pipe)((0, GenerateOutput_1.generateOutputTypes)(operationName, output), TE.chain((outputType) => writeFile(outputType, 'output.ts'))),
129
129
  generateInputType: (0, function_1.pipe)((0, GenerateInputTypes_1.generateInputTypes)(operationName, input), TE.chain((inputType) => writeFile(inputType, 'input.ts'))),
130
- operationJson: (0, GenerateOperationJson_1.generateOperationJson)(this.fileStorage, operationPath, operationName, (0, lodash_1.kebabCase)(operationName), path),
130
+ operationJson: (0, GenerateOperationJson_1.generateOperationJson)(this.fileStorage, operationPath, (0, lodash_1.snakeCase)(operationName), (0, lodash_1.kebabCase)(operationName), path),
131
131
  };
132
132
  return (0, function_1.pipe)((0, Apply_1.sequenceS)(TE.ApplicativePar)(operationFileGenerationTasks), TE.mapLeft((error) => new Error(`Failed to generate files for operation: ${operationName}: ${error}`)), TE.map(() => undefined));
133
133
  }
@@ -140,7 +140,7 @@ class OpenApiSchemaImporter {
140
140
  }), TE.chain((parameters) => this.generator.generate(`${__dirname}/templates/connector-template.zip`, process.cwd(), parameters)), TE.map(() => `/${(0, lodash_1.kebabCase)(connectorName)}`), TE.mapLeft((error) => new Error(`Failed to generate connector directory: ${error}`)));
141
141
  }
142
142
  generateOperationDirectory(connectorPath, operationName) {
143
- return (0, function_1.pipe)(TE.tryCatch(this.fileStorage.createDirectory(`${connectorPath}/src/${(0, lodash_1.kebabCase)(operationName)}`), (error) => new Error(`Failed to create operation directory: ${error}`)), TE.map(() => `${connectorPath}/src/${(0, lodash_1.kebabCase)(operationName)}`));
143
+ return (0, function_1.pipe)(TE.tryCatch(this.fileStorage.createDirectory(`${connectorPath}/src/${(0, lodash_1.snakeCase)(operationName)}`), (error) => new Error(`Failed to create operation directory: ${error}`)), TE.map(() => `${connectorPath}/src/${(0, lodash_1.snakeCase)(operationName)}`));
144
144
  }
145
145
  }
146
146
  exports.OpenApiSchemaImporter = OpenApiSchemaImporter;
@@ -1 +1 @@
1
- {"version":3,"file":"GenerateHandler.d.ts","sourceRoot":"","sources":["../../src/file-generators/GenerateHandler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,YAAY,EAAoB,MAAM,2BAA2B,CAAC;AAE3E,KAAK,iBAAiB,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;AAErE,MAAM,MAAM,oBAAoB,GAAG;IAClC,uBAAuB,EAAE,MAAM,CAAC;IAChC,uBAAuB,EAAE,MAAM,CAAC;IAChC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,UAAU,EAAE,iBAAiB,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,YAAY,CAAC;CACpB,CAAC;AAiHF,eAAO,MAAM,eAAe,wHAQzB,oBAAoB,KAAG,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAoB9C,CAAC"}
1
+ {"version":3,"file":"GenerateHandler.d.ts","sourceRoot":"","sources":["../../src/file-generators/GenerateHandler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,YAAY,EAAoB,MAAM,2BAA2B,CAAC;AAE3E,KAAK,iBAAiB,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;AAErE,MAAM,MAAM,oBAAoB,GAAG;IAClC,uBAAuB,EAAE,MAAM,CAAC;IAChC,uBAAuB,EAAE,MAAM,CAAC;IAChC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,UAAU,EAAE,iBAAiB,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,YAAY,CAAC;CACpB,CAAC;AA+IF,eAAO,MAAM,eAAe,wHAQzB,oBAAoB,KAAG,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAoB9C,CAAC"}
@@ -38,26 +38,32 @@ const getInputVariable = (name, type) => O.fold(() => `input.${name}`, (inputTyp
38
38
  })(type);
39
39
  const generateRequestHandlerInputs = (inputs, bodyInputs) => {
40
40
  if (bodyInputs.length > 0) {
41
- const constructedBodyProperty = `withBodyAsJson({ ${bodyInputs.join(',')} })`;
42
- if (inputs[0] === 'request.') {
41
+ const constructedBodyProperty = `return requestBuilder.withBodyAsJson({ ${bodyInputs.join(',')} })`;
42
+ if (inputs[0] === 'requestBuilder.') {
43
43
  const cleanInput = inputs.filter((item) => item !== '');
44
44
  return cleanInput
45
45
  .join('.')
46
- .replace('request.', `request.${constructedBodyProperty}`);
46
+ .replace('requestBuilder.', `requestBuilder.${constructedBodyProperty}`);
47
47
  }
48
48
  inputs.push(constructedBodyProperty);
49
49
  }
50
50
  else {
51
- inputs.push('withoutBody()');
51
+ inputs.push('return requestBuilder.withoutBody()');
52
52
  }
53
53
  const cleanInput = inputs.filter((item) => item !== '');
54
- return cleanInput.join('.');
54
+ return `let requestBuilder = request; ${cleanInput.join(' ')}`;
55
55
  };
56
- const constructInputs = (properties) => {
56
+ const handleOptionalInput = (inputString, name, requiredInputs) => {
57
+ if (requiredInputs.includes(name)) {
58
+ return inputString;
59
+ }
60
+ return `if(input.${name}) {${inputString}};`;
61
+ };
62
+ const constructInputs = (properties, requiredInputs) => {
57
63
  const inputsArray = Object.entries(properties);
64
+ const requiredInputsArray = O.getOrElse(() => [])(requiredInputs);
58
65
  const bodyInputs = [];
59
66
  const handlerInput = inputsArray.map(([name, input], index) => {
60
- const prefix = index === 0 ? 'request.' : '';
61
67
  let inputMapping = '';
62
68
  return O.fold(() => '', (inputIn) => {
63
69
  switch (inputIn) {
@@ -65,21 +71,21 @@ const constructInputs = (properties) => {
65
71
  bodyInputs.push(`${name}: input.${name}`);
66
72
  break;
67
73
  case 'path':
68
- inputMapping = `addPathParameter("${name}", ${getInputVariable(name, input.type)})`;
74
+ inputMapping = handleOptionalInput(`requestBuilder = requestBuilder.addPathParameter("${name}", ${getInputVariable(name, input.type)});`, name, requiredInputsArray);
69
75
  break;
70
76
  case 'query':
71
- inputMapping = `addQueryString("${name}", ${getInputVariable(name, input.type)})`;
77
+ inputMapping = handleOptionalInput(`requestBuilder = requestBuilder.addQueryString("${name}", ${getInputVariable(name, input.type)});`, name, requiredInputsArray);
72
78
  break;
73
79
  case 'header':
74
- inputMapping = `addHeader("${name}", ${getInputVariable(name, input.type)})`;
80
+ inputMapping = handleOptionalInput(`requestBuilder = requestBuilder.addHeader("${name}", ${getInputVariable(name, input.type)});`, name, requiredInputsArray);
75
81
  break;
76
82
  }
77
- return prefix + inputMapping;
83
+ return inputMapping;
78
84
  })(input.in);
79
85
  });
80
86
  return generateRequestHandlerInputs(handlerInput, bodyInputs);
81
87
  };
82
- const handleInput = (inputs) => O.fold(() => 'request.withoutBody()', (properties) => constructInputs(properties))(inputs.properties);
88
+ const handleInput = (inputs) => O.fold(() => 'request.withoutBody()', (properties) => `{${constructInputs(properties, inputs.required)}}`)(inputs.properties);
83
89
  const generatePath = (path, inputs) => O.fold(() => path, (properties) => Object.entries(properties).reduce((acc, [name, input]) => O.fold(() => acc, (inValue) => {
84
90
  if (inValue === 'path') {
85
91
  return acc.replace(`{${name}}`, `:${name}`);
@@ -116,7 +116,7 @@ describe('GenerateHandler', () => {
116
116
  handler.usingHttp((http) =>
117
117
  http
118
118
  .get("https://jsonplaceholder.typicode.com/photos/:photoId")
119
- .handleRequest((ctx, input, request) => request.addPathParameter("photoId", input.photoId).withoutBody())
119
+ .handleRequest((ctx, input, request) => {let requestBuilder = request; requestBuilder = requestBuilder.addPathParameter("photoId", input.photoId); return requestBuilder.withoutBody()})
120
120
  .handleResponse((ctx, input, response) => response.parseWithBodyAsJson())
121
121
  )
122
122
  );`)).toEqual(generatedHandler);
@@ -164,7 +164,7 @@ describe('GenerateHandler', () => {
164
164
  handler.usingHttp((http) =>
165
165
  http
166
166
  .get("https://jsonplaceholder.typicode.com/photos")
167
- .handleRequest((ctx, input, request) => request.withBodyAsJson({ photoId: input.photoId }))
167
+ .handleRequest((ctx, input, request) => {let requestBuilder = request; return requestBuilder.withBodyAsJson({ photoId: input.photoId })})
168
168
  .handleResponse((ctx, input, response) => response.parseWithBodyAsJson())
169
169
  )
170
170
  );`)).toEqual(generatedHandler);
@@ -212,7 +212,7 @@ describe('GenerateHandler', () => {
212
212
  handler.usingHttp((http) =>
213
213
  http
214
214
  .get("https://jsonplaceholder.typicode.com/photos")
215
- .handleRequest((ctx, input, request) => request.addQueryString("id", input.id).withoutBody())
215
+ .handleRequest((ctx, input, request) => {let requestBuilder = request; requestBuilder = requestBuilder.addQueryString("id", input.id); return requestBuilder.withoutBody()})
216
216
  .handleResponse((ctx, input, response) => response.parseWithBodyAsJson())
217
217
  )
218
218
  );`)).toEqual(generatedHandler);
@@ -236,7 +236,7 @@ describe('GenerateHandler', () => {
236
236
  default: O.none,
237
237
  },
238
238
  }),
239
- required: O.some(['photoId']),
239
+ required: O.some(['Content-Type']),
240
240
  additionalProperties: O.some(false),
241
241
  allOf: O.none,
242
242
  oneOf: O.none,
@@ -260,7 +260,7 @@ describe('GenerateHandler', () => {
260
260
  handler.usingHttp((http) =>
261
261
  http
262
262
  .get("https://jsonplaceholder.typicode.com/photos")
263
- .handleRequest((ctx, input, request) => request.addHeader("Content-Type", input.Content-Type).withoutBody())
263
+ .handleRequest((ctx, input, request) => {let requestBuilder = request; requestBuilder = requestBuilder.addHeader("Content-Type", input.Content-Type); return requestBuilder.withoutBody()})
264
264
  .handleResponse((ctx, input, response) => response.parseWithBodyAsJson())
265
265
  )
266
266
  );`)).toEqual(generatedHandler);
@@ -308,7 +308,7 @@ describe('GenerateHandler', () => {
308
308
  handler.usingHttp((http) =>
309
309
  http
310
310
  .get("https://jsonplaceholder.typicode.com/photos")
311
- .handleRequest((ctx, input, request) => request.addHeader("Content-Type", input.Content-Type.toString()).withoutBody())
311
+ .handleRequest((ctx, input, request) => {let requestBuilder = request; if(input.Content-Type) {requestBuilder = requestBuilder.addHeader("Content-Type", input.Content-Type.toString());}; return requestBuilder.withoutBody()})
312
312
  .handleResponse((ctx, input, response) => response.parseWithBodyAsJson())
313
313
  )
314
314
  );`)).toEqual(generatedHandler);
@@ -385,7 +385,7 @@ describe('GenerateHandler', () => {
385
385
  handler.usingHttp((http) =>
386
386
  http
387
387
  .get("https://jsonplaceholder.typicode.com/photos/:photoId/:commentId")
388
- .handleRequest((ctx, input, request) => request.addQueryString("id", input.id).addPathParameter("photoId", input.photoId).addPathParameter("commentId", input.commentId).withoutBody())
388
+ .handleRequest((ctx, input, request) => {let requestBuilder = request; if(input.id) {requestBuilder = requestBuilder.addQueryString("id", input.id);}; requestBuilder = requestBuilder.addPathParameter("photoId", input.photoId); if(input.commentId) {requestBuilder = requestBuilder.addPathParameter("commentId", input.commentId);}; return requestBuilder.withoutBody()})
389
389
  .handleResponse((ctx, input, response) => response.parseWithBodyAsJson())
390
390
  )
391
391
  );`)).toEqual(generatedHandler);
@@ -446,7 +446,68 @@ describe('GenerateHandler', () => {
446
446
  handler.usingHttp((http) =>
447
447
  http
448
448
  .get("https://jsonplaceholder.typicode.com/photos")
449
- .handleRequest((ctx, input, request) => request.addQueryString("id", input.id).withBodyAsJson({ photoId: input.photoId }))
449
+ .handleRequest((ctx, input, request) => {let requestBuilder = request; requestBuilder = requestBuilder.addQueryString("id", input.id); return requestBuilder.withBodyAsJson({ photoId: input.photoId })})
450
+ .handleResponse((ctx, input, response) => response.parseWithBodyAsJson())
451
+ )
452
+ );`)).toEqual(generatedHandler);
453
+ });
454
+ it('it should generate a handler with an optional query string and body param input', () => {
455
+ const input = {
456
+ type: O.some('object'),
457
+ title: O.none,
458
+ properties: O.some({
459
+ id: {
460
+ title: O.none,
461
+ type: O.some('string'),
462
+ in: O.some('query'),
463
+ properties: O.none,
464
+ additionalProperties: O.none,
465
+ required: O.none,
466
+ allOf: O.none,
467
+ oneOf: O.none,
468
+ anyOf: O.none,
469
+ not: O.none,
470
+ default: O.none,
471
+ },
472
+ photoId: {
473
+ title: O.none,
474
+ type: O.some('string'),
475
+ in: O.some('body'),
476
+ properties: O.none,
477
+ additionalProperties: O.none,
478
+ required: O.none,
479
+ allOf: O.none,
480
+ oneOf: O.none,
481
+ anyOf: O.none,
482
+ not: O.none,
483
+ default: O.none,
484
+ },
485
+ }),
486
+ required: O.some(['photoId']),
487
+ additionalProperties: O.some(false),
488
+ allOf: O.none,
489
+ oneOf: O.none,
490
+ anyOf: O.none,
491
+ not: O.none,
492
+ in: O.none,
493
+ default: O.none,
494
+ };
495
+ const payload = getGenerateHandlerInput({ input });
496
+ const generatedHandler = (0, GenerateHandler_1.generateHandler)(payload);
497
+ expect(E.right(`import { OperationHandlerSetup } from "@trayio/cdk-dsl/connector/operation/OperationHandlerSetup";
498
+ import { OpenApiTestAuth } from "../OpenApiTestAuth";
499
+ import { GetPhotoInput } from "./input";
500
+ import { GetPhotoOutput } from "./output";
501
+
502
+ export const getPhotoHandler = OperationHandlerSetup.configureHandler<
503
+ OpenApiTestAuth,
504
+ GetPhotoInput,
505
+ GetPhotoOutput
506
+ >((handler) =>
507
+ handler.usingHttp((http) =>
508
+ http
509
+ .get("https://jsonplaceholder.typicode.com/photos")
510
+ .handleRequest((ctx, input, request) => {let requestBuilder = request; if(input.id) {requestBuilder = requestBuilder.addQueryString("id", input.id);}; return requestBuilder.withBodyAsJson({ photoId: input.photoId })})
450
511
  .handleResponse((ctx, input, response) => response.parseWithBodyAsJson())
451
512
  )
452
513
  );`)).toEqual(generatedHandler);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trayio/tray-openapi",
3
- "version": "4.4.0",
3
+ "version": "4.4.1",
4
4
  "description": "Creating CDK Projects from OpenAPI 3.0 Schemas",
5
5
  "exports": {
6
6
  "./*": "./dist/*.js"