@trayio/tray-openapi 2.4.0 → 2.5.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 (34) hide show
  1. package/dist/GenerateHander.test.js +18 -27
  2. package/dist/GenerateHandler.d.ts +2 -2
  3. package/dist/GenerateHandler.d.ts.map +1 -1
  4. package/dist/GenerateHandler.js +3 -14
  5. package/dist/OpenApiSchemaImporter.d.ts +9 -4
  6. package/dist/OpenApiSchemaImporter.d.ts.map +1 -1
  7. package/dist/OpenApiSchemaImporter.js +41 -21
  8. package/dist/OpenApiSchemaImporter.test.js +4 -2
  9. package/dist/OpenApiTypeDescriptors.d.ts +22 -13
  10. package/dist/OpenApiTypeDescriptors.d.ts.map +1 -1
  11. package/dist/OpenApiTypeDescriptors.js +26 -4
  12. package/dist/connector/JsonSchemaToTypescriptOptions.d.ts +9 -0
  13. package/dist/connector/JsonSchemaToTypescriptOptions.d.ts.map +1 -0
  14. package/dist/connector/JsonSchemaToTypescriptOptions.js +11 -0
  15. package/dist/connector/input/GenerateInput.d.ts +8 -0
  16. package/dist/connector/input/GenerateInput.d.ts.map +1 -0
  17. package/dist/connector/input/GenerateInput.js +8 -0
  18. package/dist/connector/input/GenerateInput.test.d.ts +2 -0
  19. package/dist/connector/input/GenerateInput.test.d.ts.map +1 -0
  20. package/dist/connector/input/GenerateInput.test.js +133 -0
  21. package/dist/connector/input/ProcessInput.d.ts +4 -0
  22. package/dist/connector/input/ProcessInput.d.ts.map +1 -0
  23. package/dist/connector/input/ProcessInput.js +81 -0
  24. package/dist/connector/input/ProcessInput.test.d.ts +2 -0
  25. package/dist/connector/input/ProcessInput.test.d.ts.map +1 -0
  26. package/dist/connector/input/ProcessInput.test.js +227 -0
  27. package/dist/connector/input/TransformInput.d.ts +4 -0
  28. package/dist/connector/input/TransformInput.d.ts.map +1 -0
  29. package/dist/connector/input/TransformInput.js +54 -0
  30. package/dist/connector/input/TransformInput.test.d.ts +2 -0
  31. package/dist/connector/input/TransformInput.test.d.ts.map +1 -0
  32. package/dist/connector/input/TransformInput.test.js +75 -0
  33. package/dist/templates/connector-template.zip +0 -0
  34. package/package.json +6 -2
@@ -22,23 +22,14 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
- return new (P || (P = Promise))(function (resolve, reject) {
28
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
- step((generator = generator.apply(thisArg, _arguments || [])).next());
32
- });
33
- };
34
25
  Object.defineProperty(exports, "__esModule", { value: true });
35
26
  const E = __importStar(require("fp-ts/Either"));
36
27
  const GenerateHandler_1 = require("./GenerateHandler");
37
28
  const getGenerateHandlerInput = (input) => (Object.assign({ connectorNamePascalCase: 'OpenApiTest', operationNamePascalCase: 'GetPhoto', operationNameCamelCase: 'getPhoto', httpMethod: 'get', baseUrl: 'https://jsonplaceholder.typicode.com/', input: [], path: 'photos' }, input));
38
29
  describe('GenerateHandler', () => {
39
- it('it should generate a handler', () => __awaiter(void 0, void 0, void 0, function* () {
30
+ it('it should generate a handler', () => {
40
31
  const payload = getGenerateHandlerInput({});
41
- const generatedHandler = yield (0, GenerateHandler_1.generateHandler)(payload)();
32
+ const generatedHandler = (0, GenerateHandler_1.generateHandler)(payload);
42
33
  expect(E.right(`import { OperationHandlerSetup } from "@trayio/cdk-dsl/connector/operation/OperationHandlerSetup";
43
34
  import { OpenApiTest } from "../OpenApiTest";
44
35
  import { GetPhotoInput } from "./input";
@@ -56,11 +47,11 @@ describe('GenerateHandler', () => {
56
47
  .handleResponse((response) => response.parseWithBodyAsJson())
57
48
  )
58
49
  );`)).toEqual(generatedHandler);
59
- }));
60
- it('it should generate a handler with a path parameter', () => __awaiter(void 0, void 0, void 0, function* () {
50
+ });
51
+ it('it should generate a handler with a path parameter', () => {
61
52
  const input = [{ type: 'string', name: 'photoId', in: 'path' }];
62
53
  const payload = getGenerateHandlerInput({ input });
63
- const generatedHandler = yield (0, GenerateHandler_1.generateHandler)(payload)();
54
+ const generatedHandler = (0, GenerateHandler_1.generateHandler)(payload);
64
55
  expect(E.right(`import { OperationHandlerSetup } from "@trayio/cdk-dsl/connector/operation/OperationHandlerSetup";
65
56
  import { OpenApiTest } from "../OpenApiTest";
66
57
  import { GetPhotoInput } from "./input";
@@ -78,11 +69,11 @@ describe('GenerateHandler', () => {
78
69
  .handleResponse((response) => response.parseWithBodyAsJson())
79
70
  )
80
71
  );`)).toEqual(generatedHandler);
81
- }));
82
- it('it should generate a handler with a body input as json', () => __awaiter(void 0, void 0, void 0, function* () {
72
+ });
73
+ it('it should generate a handler with a body input as json', () => {
83
74
  const input = [{ type: 'object', name: 'payload', in: 'body' }];
84
75
  const payload = getGenerateHandlerInput({ input });
85
- const generatedHandler = yield (0, GenerateHandler_1.generateHandler)(payload)();
76
+ const generatedHandler = (0, GenerateHandler_1.generateHandler)(payload);
86
77
  expect(E.right(`import { OperationHandlerSetup } from "@trayio/cdk-dsl/connector/operation/OperationHandlerSetup";
87
78
  import { OpenApiTest } from "../OpenApiTest";
88
79
  import { GetPhotoInput } from "./input";
@@ -100,11 +91,11 @@ describe('GenerateHandler', () => {
100
91
  .handleResponse((response) => response.parseWithBodyAsJson())
101
92
  )
102
93
  );`)).toEqual(generatedHandler);
103
- }));
104
- it('it should generate a handler with a query string input', () => __awaiter(void 0, void 0, void 0, function* () {
94
+ });
95
+ it('it should generate a handler with a query string input', () => {
105
96
  const input = [{ type: 'string', name: 'id', in: 'query' }];
106
97
  const payload = getGenerateHandlerInput({ input });
107
- const generatedHandler = yield (0, GenerateHandler_1.generateHandler)(payload)();
98
+ const generatedHandler = (0, GenerateHandler_1.generateHandler)(payload);
108
99
  expect(E.right(`import { OperationHandlerSetup } from "@trayio/cdk-dsl/connector/operation/OperationHandlerSetup";
109
100
  import { OpenApiTest } from "../OpenApiTest";
110
101
  import { GetPhotoInput } from "./input";
@@ -122,13 +113,13 @@ describe('GenerateHandler', () => {
122
113
  .handleResponse((response) => response.parseWithBodyAsJson())
123
114
  )
124
115
  );`)).toEqual(generatedHandler);
125
- }));
126
- it('it should generate a handler with a header input', () => __awaiter(void 0, void 0, void 0, function* () {
116
+ });
117
+ it('it should generate a handler with a header input', () => {
127
118
  const input = [
128
119
  { type: 'string', name: 'Content-Type', in: 'header' },
129
120
  ];
130
121
  const payload = getGenerateHandlerInput({ input });
131
- const generatedHandler = yield (0, GenerateHandler_1.generateHandler)(payload)();
122
+ const generatedHandler = (0, GenerateHandler_1.generateHandler)(payload);
132
123
  expect(E.right(`import { OperationHandlerSetup } from "@trayio/cdk-dsl/connector/operation/OperationHandlerSetup";
133
124
  import { OpenApiTest } from "../OpenApiTest";
134
125
  import { GetPhotoInput } from "./input";
@@ -146,15 +137,15 @@ describe('GenerateHandler', () => {
146
137
  .handleResponse((response) => response.parseWithBodyAsJson())
147
138
  )
148
139
  );`)).toEqual(generatedHandler);
149
- }));
150
- it('it should generate a handler with a query string and path param input', () => __awaiter(void 0, void 0, void 0, function* () {
140
+ });
141
+ it('it should generate a handler with a query string and path param input', () => {
151
142
  const input = [
152
143
  { type: 'string', name: 'id', in: 'query' },
153
144
  { type: 'string', name: 'photoId', in: 'path' },
154
145
  { type: 'string', name: 'commentId', in: 'path' },
155
146
  ];
156
147
  const payload = getGenerateHandlerInput({ input });
157
- const generatedHandler = yield (0, GenerateHandler_1.generateHandler)(payload)();
148
+ const generatedHandler = (0, GenerateHandler_1.generateHandler)(payload);
158
149
  expect(E.right(`import { OperationHandlerSetup } from "@trayio/cdk-dsl/connector/operation/OperationHandlerSetup";
159
150
  import { OpenApiTest } from "../OpenApiTest";
160
151
  import { GetPhotoInput } from "./input";
@@ -172,5 +163,5 @@ describe('GenerateHandler', () => {
172
163
  .handleResponse((response) => response.parseWithBodyAsJson())
173
164
  )
174
165
  );`)).toEqual(generatedHandler);
175
- }));
166
+ });
176
167
  });
@@ -1,4 +1,4 @@
1
- import * as TE from 'fp-ts/TaskEither';
1
+ import * as E from 'fp-ts/Either';
2
2
  type InputMethod = 'path' | 'query' | 'body' | 'header';
3
3
  type HandlerHttpMethod = 'get' | 'post' | 'put' | 'patch' | 'delete';
4
4
  type Input = {
@@ -15,6 +15,6 @@ export type GenerateHandlerInput = {
15
15
  path: string;
16
16
  input: Input[];
17
17
  };
18
- export declare const generateHandler: ({ connectorNamePascalCase, operationNamePascalCase, operationNameCamelCase, httpMethod, baseUrl, path, input, }: GenerateHandlerInput) => TE.TaskEither<Error, string>;
18
+ export declare const generateHandler: ({ connectorNamePascalCase, operationNamePascalCase, operationNameCamelCase, httpMethod, baseUrl, path, input, }: GenerateHandlerInput) => E.Either<Error, string>;
19
19
  export {};
20
20
  //# sourceMappingURL=GenerateHandler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"GenerateHandler.d.ts","sourceRoot":"","sources":["../src/GenerateHandler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEvC,KAAK,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;AAExD,KAAK,iBAAiB,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;AAErE,KAAK,KAAK,GAAG;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,WAAW,CAAC;CAChB,CAAC;AAEF,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,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,KAAK,EAAE,CAAC;CACf,CAAC;AAyCF,eAAO,MAAM,eAAe,oHAQzB,oBAAoB,KAAG,GAAG,UAAU,CAAC,KAAK,EAAE,MAAM,CAoBnD,CAAC"}
1
+ {"version":3,"file":"GenerateHandler.d.ts","sourceRoot":"","sources":["../src/GenerateHandler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAElC,KAAK,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;AAExD,KAAK,iBAAiB,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;AAErE,KAAK,KAAK,GAAG;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,WAAW,CAAC;CAChB,CAAC;AAEF,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,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,KAAK,EAAE,CAAC;CACf,CAAC;AAyCF,eAAO,MAAM,eAAe,oHAQzB,oBAAoB,KAAG,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAoB9C,CAAC"}
@@ -22,18 +22,9 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
- return new (P || (P = Promise))(function (resolve, reject) {
28
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
- step((generator = generator.apply(thisArg, _arguments || [])).next());
32
- });
33
- };
34
25
  Object.defineProperty(exports, "__esModule", { value: true });
35
26
  exports.generateHandler = void 0;
36
- const TE = __importStar(require("fp-ts/TaskEither"));
27
+ const E = __importStar(require("fp-ts/Either"));
37
28
  const handleInput = (inputs) => {
38
29
  if (!inputs.length) {
39
30
  return 'request';
@@ -65,8 +56,7 @@ const generatePath = (path, inputs) => inputs.reduce((acc, input) => {
65
56
  }
66
57
  return acc;
67
58
  }, path);
68
- const generateHandler = ({ connectorNamePascalCase, operationNamePascalCase, operationNameCamelCase, httpMethod, baseUrl, path, input, }) => TE.tryCatch(() => __awaiter(void 0, void 0, void 0, function* () {
69
- return `import { OperationHandlerSetup } from "@trayio/cdk-dsl/connector/operation/OperationHandlerSetup";
59
+ const generateHandler = ({ connectorNamePascalCase, operationNamePascalCase, operationNameCamelCase, httpMethod, baseUrl, path, input, }) => E.tryCatch(() => `import { OperationHandlerSetup } from "@trayio/cdk-dsl/connector/operation/OperationHandlerSetup";
70
60
  import { ${connectorNamePascalCase} } from "../${connectorNamePascalCase}";
71
61
  import { ${operationNamePascalCase}Input } from "./input";
72
62
  import { ${operationNamePascalCase}Output } from "./output";
@@ -82,6 +72,5 @@ const generateHandler = ({ connectorNamePascalCase, operationNamePascalCase, ope
82
72
  .handleRequest((ctx, input, request) => ${handleInput(input)})
83
73
  .handleResponse((response) => response.parseWithBodyAsJson())
84
74
  )
85
- );`;
86
- }), (error) => new Error(`Failed to generate handler: ${error}`));
75
+ );`, (error) => new Error(`Failed to generate handler: ${error}`));
87
76
  exports.generateHandler = generateHandler;
@@ -1,8 +1,13 @@
1
1
  import * as TE from 'fp-ts/TaskEither';
2
- import { OpenAPISchema } from './OpenApiTypeDescriptors';
2
+ import { Generator } from '@trayio/generator/generator/Generator';
3
3
  export declare class OpenApiSchemaImporter {
4
- buildConnector(openApiSpecPath: string): TE.TaskEither<Error, undefined>;
5
- getOpenApiSpec(openApiSpecPath: string): TE.TaskEither<Error, OpenAPISchema>;
6
- generateHandlerFile(openApiSpec: OpenAPISchema): TE.TaskEither<Error, undefined>;
4
+ private generator;
5
+ constructor(generator: Generator);
6
+ buildConnector(openApiSpecPath: string, connectorName: string): TE.TaskEither<Error, undefined>;
7
+ private generateOperationFromPath;
8
+ private getOpenApiSpec;
9
+ private generateHandlerFile;
10
+ private generateConnectorDirectory;
11
+ private generateOperationDirectory;
7
12
  }
8
13
  //# sourceMappingURL=OpenApiSchemaImporter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"OpenApiSchemaImporter.d.ts","sourceRoot":"","sources":["../src/OpenApiSchemaImporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAIvC,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAIzD,qBAAa,qBAAqB;IACjC,cAAc,CAAC,eAAe,EAAE,MAAM,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,SAAS,CAAC;IAOxE,cAAc,CAAC,eAAe,EAAE,MAAM,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,aAAa,CAAC;IAwB5E,mBAAmB,CAClB,WAAW,EAAE,aAAa,GACxB,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,SAAS,CAAC;CA2BlC"}
1
+ {"version":3,"file":"OpenApiSchemaImporter.d.ts","sourceRoot":"","sources":["../src/OpenApiSchemaImporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAQvC,OAAO,EAAE,SAAS,EAAE,MAAM,uCAAuC,CAAC;AAclE,qBAAa,qBAAqB;IACrB,OAAO,CAAC,SAAS;gBAAT,SAAS,EAAE,SAAS;IAExC,cAAc,CACb,eAAe,EAAE,MAAM,EACvB,aAAa,EAAE,MAAM,GACnB,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,SAAS,CAAC;IAoClC,OAAO,CAAC,yBAAyB;IA+BjC,OAAO,CAAC,cAAc;IAwBtB,OAAO,CAAC,mBAAmB;IAoC3B,OAAO,CAAC,0BAA0B;IAwBlC,OAAO,CAAC,0BAA0B;CAalC"}
@@ -22,40 +22,60 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
- return new (P || (P = Promise))(function (resolve, reject) {
28
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
- step((generator = generator.apply(thisArg, _arguments || [])).next());
32
- });
33
- };
34
25
  Object.defineProperty(exports, "__esModule", { value: true });
35
26
  exports.OpenApiSchemaImporter = void 0;
36
27
  const TE = __importStar(require("fp-ts/TaskEither"));
28
+ const E = __importStar(require("fp-ts/Either"));
37
29
  const function_1 = require("fp-ts/function");
38
30
  const fse = __importStar(require("fs-extra"));
31
+ const Array_1 = require("fp-ts/Array");
32
+ const StringExtensions_1 = require("@trayio/commons/string/StringExtensions");
33
+ const lodash_1 = require("lodash");
39
34
  const Task_1 = require("@trayio/commons/task/Task");
40
35
  const OpenApiCodecs_1 = require("./OpenApiCodecs");
41
36
  const GenerateHandler_1 = require("./GenerateHandler");
42
37
  class OpenApiSchemaImporter {
43
- buildConnector(openApiSpecPath) {
44
- return (0, function_1.pipe)(this.getOpenApiSpec(openApiSpecPath), TE.chain((openApiSpec) => this.generateHandlerFile(openApiSpec)));
38
+ constructor(generator) {
39
+ this.generator = generator;
40
+ }
41
+ buildConnector(openApiSpecPath, connectorName) {
42
+ return (0, function_1.pipe)(this.generateConnectorDirectory(connectorName), TE.bindTo('connectorPath'), TE.bind('openApiSpec', () => (0, Task_1.createTaskEitherFromEither)(this.getOpenApiSpec(openApiSpecPath))), TE.bind('paths', ({ openApiSpec }) => TE.right(Object.keys(openApiSpec.paths).map((path) => ({
43
+ path,
44
+ routes: Object.keys(openApiSpec.paths[path]).map((route) => ({
45
+ method: route,
46
+ path: openApiSpec.paths[path][route],
47
+ })),
48
+ })))), TE.map(({ openApiSpec, connectorPath, paths }) => (0, Array_1.traverse)(TE.ApplicativeSeq)((path) => (0, Task_1.createTaskEitherFromEither)(this.generateOperationFromPath(path, connectorPath, openApiSpec.servers[0].url, connectorName)))(paths)), TE.map(() => undefined));
49
+ }
50
+ generateOperationFromPath(path, connectorPath, baseUrl, connectorName) {
51
+ return (0, function_1.pipe)((0, Array_1.traverse)(E.Applicative)((route) => (0, function_1.pipe)(this.generateOperationDirectory(connectorPath, route.path.operationId), E.chain((operationPath) => this.generateHandlerFile(operationPath, route.method, baseUrl, path.path, connectorName, route.path.operationId)), E.map(() => undefined)))(path.routes), E.map(() => undefined));
45
52
  }
46
53
  getOpenApiSpec(openApiSpecPath) {
47
- return (0, function_1.pipe)(TE.tryCatch(() => __awaiter(this, void 0, void 0, function* () { return fse.readFileSync(openApiSpecPath, 'utf-8'); }), (error) => new Error(`Failed to read OpenAPI spec from path ${openApiSpecPath}: ${error}`)), TE.chain((openApiSpec) => TE.tryCatch(() => __awaiter(this, void 0, void 0, function* () { return JSON.parse(openApiSpec); }), (error) => new Error(`Failed to parse OpenAPI spec as JSON from path ${openApiSpecPath}: ${error}`))), TE.chain((openApiSpec) => (0, Task_1.createTaskEitherFromEither)(OpenApiCodecs_1.openApiSpecCodec.decode(openApiSpec))));
54
+ return (0, function_1.pipe)(E.tryCatch(() => fse.readFileSync(openApiSpecPath, 'utf-8'), (error) => new Error(`Failed to read OpenAPI spec from path ${openApiSpecPath}: ${error}`)), E.chain((openApiSpec) => E.tryCatch(() => JSON.parse(openApiSpec), (error) => new Error(`Failed to parse OpenAPI spec as JSON from path ${openApiSpecPath}: ${error}`))), E.chain((openApiSpec) => OpenApiCodecs_1.openApiSpecCodec.decode(openApiSpec)));
48
55
  }
49
- generateHandlerFile(openApiSpec) {
50
- return (0, function_1.pipe)(TE.right({
51
- connectorNamePascalCase: 'test',
52
- operationNameCamelCase: 'test',
53
- operationNamePascalCase: 'test',
54
- httpMethod: 'get',
55
- baseUrl: 'https://jsonplaceholder.typicode.com/',
56
- path: 'test',
56
+ generateHandlerFile(operationPath, httpMethod, baseUrl, path, connectorName, operationName) {
57
+ return (0, function_1.pipe)(E.right({
58
+ connectorNamePascalCase: StringExtensions_1.StringExtensions.pascalCase(connectorName),
59
+ operationNameCamelCase: (0, lodash_1.camelCase)(operationName),
60
+ operationNamePascalCase: StringExtensions_1.StringExtensions.pascalCase(operationName),
61
+ httpMethod,
62
+ baseUrl,
63
+ path,
57
64
  input: [],
58
- }), TE.chain((parameters) => (0, GenerateHandler_1.generateHandler)(parameters)), TE.chain((handler) => TE.tryCatch(() => __awaiter(this, void 0, void 0, function* () { return fse.writeFileSync(`${__dirname}/handler.ts`, handler, 'utf-8'); }), (error) => new Error(`Failed to write handler to file system: ${error}`))), TE.map(() => undefined), TE.mapLeft((error) => new Error(`Failed to generate handler for operation: ${error}`)));
65
+ }), E.chain((parameters) => (0, GenerateHandler_1.generateHandler)(parameters)), E.chain((handler) => E.tryCatch(() => {
66
+ fse.writeFileSync(`${operationPath}/handler.ts`, handler, 'utf-8');
67
+ }, (error) => new Error(`Failed to write handler to file system: ${error}`))), E.map(() => undefined), E.mapLeft((error) => new Error(`Failed to generate handler for operation: ${error}`)));
68
+ }
69
+ generateConnectorDirectory(connectorName) {
70
+ return (0, function_1.pipe)(TE.right({
71
+ connectorNameTitleCase: StringExtensions_1.StringExtensions.titleCase(connectorName),
72
+ connectorNameKebabCase: (0, lodash_1.kebabCase)(connectorName),
73
+ connectorNamePascalCase: StringExtensions_1.StringExtensions.pascalCase(connectorName),
74
+ connectorNameCamelCase: (0, lodash_1.camelCase)(connectorName),
75
+ }), TE.chain((parameters) => this.generator.generate(`${__dirname}/templates/connector-template.zip`, `${process.cwd()}/test`, parameters)), TE.map(() => `${process.cwd()}/test/${(0, lodash_1.kebabCase)(connectorName)}`), TE.mapLeft((error) => new Error(`Failed to generate connector directory: ${error}`)));
76
+ }
77
+ generateOperationDirectory(connectorPath, operationName) {
78
+ return (0, function_1.pipe)(E.tryCatch(() => fse.ensureDirSync(`${connectorPath}/src/${(0, lodash_1.kebabCase)(operationName)}`), (error) => new Error(`Failed to create operation directory: ${error}`)), E.map(() => `${connectorPath}/src/${(0, lodash_1.kebabCase)(operationName)}`));
59
79
  }
60
80
  }
61
81
  exports.OpenApiSchemaImporter = OpenApiSchemaImporter;
@@ -9,11 +9,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
+ const NodeFsGenerator_1 = require("@trayio/generator/generator/NodeFsGenerator");
12
13
  const OpenApiSchemaImporter_1 = require("./OpenApiSchemaImporter");
13
14
  describe('openApiSchemaImporter', () => {
14
- const openApiSchemaImporter = new OpenApiSchemaImporter_1.OpenApiSchemaImporter();
15
+ const generator = new NodeFsGenerator_1.NodeFsGenerator();
16
+ const openApiSchemaImporter = new OpenApiSchemaImporter_1.OpenApiSchemaImporter(generator);
15
17
  it('should decode the openApiSpec', () => __awaiter(void 0, void 0, void 0, function* () {
16
- const schema = yield openApiSchemaImporter.buildConnector(`${__dirname}/single-get-openapi.json`)();
18
+ const schema = yield openApiSchemaImporter.buildConnector(`${__dirname}/single-get-openapi.json`, 'testConnector')();
17
19
  expect(schema._tag).toEqual('Right');
18
20
  }));
19
21
  });
@@ -1,20 +1,29 @@
1
1
  import * as t from 'io-ts';
2
- type Path = {
2
+ import * as O from 'fp-ts/Option';
3
+ export type Path = {
3
4
  description: string;
4
5
  tags: string[];
5
6
  operationId: string;
6
- parameters: {
7
- name: string;
8
- in: string;
9
- description: string;
10
- required: boolean;
11
- schema: {
12
- type: string;
13
- format?: string;
14
- };
15
- additionalProperties?: boolean;
16
- }[];
7
+ parameters: O.Option<Parameter[]>;
8
+ requestBody: O.Option<RequestBody>;
9
+ };
10
+ export type Parameter = {
11
+ name: string;
12
+ in: string;
13
+ description: string;
14
+ required: boolean;
15
+ schema: {
16
+ type: string;
17
+ format: O.Option<string>;
18
+ };
19
+ };
20
+ export type RequestBody = {
21
+ content: Record<string, MediaType>;
22
+ };
23
+ type MediaType = {
24
+ schema: ArraySchema | ObjectSchema;
17
25
  };
26
+ export type OpenApiHttpMethod = 'get' | 'post' | 'put' | 'patch' | 'delete';
18
27
  type ArraySchema = {
19
28
  type: 'array';
20
29
  items: {
@@ -42,7 +51,7 @@ export type OpenAPISchema = {
42
51
  servers: {
43
52
  url: string;
44
53
  }[];
45
- paths: Record<string, Record<string, Path>>;
54
+ paths: Record<string, Partial<Record<OpenApiHttpMethod, Path>>>;
46
55
  components: ComponentSchema;
47
56
  };
48
57
  export declare const openApiSpecTypeDescriptor: t.Type<OpenAPISchema, unknown>;
@@ -1 +1 @@
1
- {"version":3,"file":"OpenApiTypeDescriptors.d.ts","sourceRoot":"","sources":["../src/OpenApiTypeDescriptors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,OAAO,CAAC;AAE3B,KAAK,IAAI,GAAG;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,EAAE,EAAE,MAAM,CAAC;QACX,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,OAAO,CAAC;QAClB,MAAM,EAAE;YACP,IAAI,EAAE,MAAM,CAAC;YACb,MAAM,CAAC,EAAE,MAAM,CAAC;SAChB,CAAC;QACF,oBAAoB,CAAC,EAAE,OAAO,CAAC;KAC/B,EAAE,CAAC;CACJ,CAAC;AAEF,KAAK,WAAW,GAAG;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;KACb,CAAC;CACF,CAAC;AAEF,KAAK,YAAY,GAAG;IACnB,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CAC3C,CAAC;AAEF,KAAK,cAAc,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,WAAW,GAAG,YAAY,CAAC;AAEpE,KAAK,eAAe,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,YAAY,CAAC,CAAA;CAAE,CAAC;AAE/E,MAAM,MAAM,aAAa,GAAG;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,OAAO,EAAE;QACR,GAAG,EAAE,MAAM,CAAC;KACZ,EAAE,CAAC;IACJ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;IAC5C,UAAU,EAAE,eAAe,CAAC;CAC5B,CAAC;AA0CF,eAAO,MAAM,yBAAyB,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE,OAAO,CAWpE,CAAC"}
1
+ {"version":3,"file":"OpenApiTypeDescriptors.d.ts","sourceRoot":"","sources":["../src/OpenApiTypeDescriptors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,OAAO,CAAC;AAE3B,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAGlC,MAAM,MAAM,IAAI,GAAG;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;IAClC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;KACzB,CAAC;CACF,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACzB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACnC,CAAC;AAEF,KAAK,SAAS,GAAG;IAChB,MAAM,EAAE,WAAW,GAAG,YAAY,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE5E,KAAK,WAAW,GAAG;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;KACb,CAAC;CACF,CAAC;AAEF,KAAK,YAAY,GAAG;IACnB,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CAC3C,CAAC;AAEF,KAAK,cAAc,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,WAAW,GAAG,YAAY,CAAC;AAEpE,KAAK,eAAe,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,YAAY,CAAC,CAAA;CAAE,CAAC;AAE/E,MAAM,MAAM,aAAa,GAAG;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,OAAO,EAAE;QACR,GAAG,EAAE,MAAM,CAAC;KACZ,EAAE,CAAC;IACJ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAChE,UAAU,EAAE,eAAe,CAAC;CAC5B,CAAC;AAoEF,eAAO,MAAM,yBAAyB,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE,OAAO,CAWpE,CAAC"}
@@ -25,34 +25,56 @@ var __importStar = (this && this.__importStar) || function (mod) {
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.openApiSpecTypeDescriptor = void 0;
27
27
  const t = __importStar(require("io-ts"));
28
+ const io_ts_types_1 = require("io-ts-types");
29
+ const TypeCodec_1 = require("@trayio/commons/codec/TypeCodec");
28
30
  const openApiSpecPropertySchemaTypeDescriptor = t.type({ type: t.string });
29
31
  const openApiSpecObjectSchemaTypeDescriptor = t.type({
30
32
  type: t.literal('object'),
31
33
  properties: t.record(t.string, openApiSpecPropertySchemaTypeDescriptor),
32
34
  });
33
35
  const openApiSpecArraySchemaTypeDescriptor = t.type({ type: t.literal('array'), items: t.any });
36
+ const openApiSpecMediaTypeTypeDescriptor = t.type({
37
+ schema: t.union([
38
+ openApiSpecObjectSchemaTypeDescriptor,
39
+ openApiSpecArraySchemaTypeDescriptor,
40
+ ]),
41
+ });
34
42
  const openApiSpecComponentSchemaTypeDescriptor = t.type({
35
43
  schemas: t.record(t.string, t.union([
36
44
  openApiSpecObjectSchemaTypeDescriptor,
37
45
  openApiSpecArraySchemaTypeDescriptor,
38
46
  ])),
39
47
  });
48
+ const openApiSpecRequestBodyTypeDescriptor = t.type({
49
+ content: t.record(t.string, openApiSpecMediaTypeTypeDescriptor),
50
+ });
40
51
  const openApiSpecPathTypeDescriptor = t.type({
41
52
  description: t.string,
42
53
  tags: t.array(t.string),
43
54
  operationId: t.string,
44
- parameters: t.array(t.type({
55
+ parameters: (0, io_ts_types_1.optionFromNullable)(t.array(t.type({
45
56
  name: t.string,
46
57
  in: t.string,
47
58
  description: t.string,
48
59
  required: t.boolean,
49
- schema: t.type({ type: t.string }),
50
- })),
60
+ schema: t.type({
61
+ type: t.string,
62
+ format: (0, io_ts_types_1.optionFromNullable)(t.string),
63
+ }),
64
+ }))),
65
+ requestBody: (0, io_ts_types_1.optionFromNullable)(openApiSpecRequestBodyTypeDescriptor),
66
+ });
67
+ const httpKeys = t.keyof({
68
+ get: null,
69
+ post: null,
70
+ put: null,
71
+ patch: null,
72
+ delete: null,
51
73
  });
52
74
  exports.openApiSpecTypeDescriptor = t.type({
53
75
  openapi: t.string,
54
76
  info: t.type({ title: t.string, description: t.string, version: t.string }),
55
77
  servers: t.array(t.type({ url: t.string })),
56
- paths: t.record(t.string, t.record(t.string, openApiSpecPathTypeDescriptor)),
78
+ paths: t.record(t.string, TypeCodec_1.TypeCodec.partialRecord(httpKeys, openApiSpecPathTypeDescriptor)),
57
79
  components: openApiSpecComponentSchemaTypeDescriptor,
58
80
  });
@@ -0,0 +1,9 @@
1
+ export declare const JsonSchemaToTypescriptOptions: {
2
+ bannerComment: string;
3
+ format: boolean;
4
+ style: {
5
+ singleQuote: boolean;
6
+ useTabs: boolean;
7
+ };
8
+ };
9
+ //# sourceMappingURL=JsonSchemaToTypescriptOptions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JsonSchemaToTypescriptOptions.d.ts","sourceRoot":"","sources":["../../src/connector/JsonSchemaToTypescriptOptions.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,6BAA6B;;;;;;;CAOzC,CAAC"}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JsonSchemaToTypescriptOptions = void 0;
4
+ exports.JsonSchemaToTypescriptOptions = {
5
+ bannerComment: '',
6
+ format: true,
7
+ style: {
8
+ singleQuote: true,
9
+ useTabs: true,
10
+ },
11
+ };
@@ -0,0 +1,8 @@
1
+ import { JSONSchema4 } from 'json-schema';
2
+ import * as TE from 'fp-ts/TaskEither';
3
+ export type GenerateInputParams = {
4
+ operationNameCamelCase: string;
5
+ parameters: JSONSchema4;
6
+ };
7
+ export declare const generateInput: ({ operationNameCamelCase, parameters, }: GenerateInputParams) => TE.TaskEither<Error, string>;
8
+ //# sourceMappingURL=GenerateInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GenerateInput.d.ts","sourceRoot":"","sources":["../../../src/connector/input/GenerateInput.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAGvC,MAAM,MAAM,mBAAmB,GAAG;IACjC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,UAAU,EAAE,WAAW,CAAC;CACxB,CAAC;AAEF,eAAO,MAAM,aAAa,4CAGvB,mBAAmB,KAAG,GAAG,UAAU,CAAC,KAAK,EAAE,MAAM,CASlD,CAAC"}
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateInput = void 0;
4
+ const json_schema_to_typescript_1 = require("json-schema-to-typescript");
5
+ const TaskEither_1 = require("fp-ts/TaskEither");
6
+ const JsonSchemaToTypescriptOptions_1 = require("../JsonSchemaToTypescriptOptions");
7
+ const generateInput = ({ operationNameCamelCase, parameters, }) => (0, TaskEither_1.tryCatch)(() => (0, json_schema_to_typescript_1.compile)(parameters, `${operationNameCamelCase}Input`, JsonSchemaToTypescriptOptions_1.JsonSchemaToTypescriptOptions), (reason) => new Error(`${reason}`));
8
+ exports.generateInput = generateInput;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=GenerateInput.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GenerateInput.test.d.ts","sourceRoot":"","sources":["../../../src/connector/input/GenerateInput.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ const TE = __importStar(require("fp-ts/TaskEither"));
36
+ const GenerateInput_1 = require("./GenerateInput");
37
+ describe('Input: GenerateInput', () => {
38
+ it('it should generate input.ts file contents when given JSON schema path and query params', () => __awaiter(void 0, void 0, void 0, function* () {
39
+ const operationNameCamelCase = 'getPost';
40
+ const parameters = {
41
+ type: 'object',
42
+ properties: {
43
+ id: {
44
+ type: 'integer',
45
+ },
46
+ filter: {
47
+ type: 'string',
48
+ },
49
+ },
50
+ required: ['id'],
51
+ additionalProperties: false,
52
+ };
53
+ const generatedInput = (0, GenerateInput_1.generateInput)({
54
+ operationNameCamelCase,
55
+ parameters,
56
+ });
57
+ const generatedInputFile = yield TE.getOrElse((error) => {
58
+ throw new Error('Should have been right');
59
+ })(generatedInput)();
60
+ const expected = `export interface GetPostInput {
61
+ id: number;
62
+ filter?: string;
63
+ }
64
+ `;
65
+ expect(generatedInputFile).toEqual(expected);
66
+ }));
67
+ it('it should generate input.ts file contents when given JSON schema optional path and query params', () => __awaiter(void 0, void 0, void 0, function* () {
68
+ const operationNameCamelCase = 'getPost';
69
+ const parameters = {
70
+ type: 'object',
71
+ properties: {
72
+ id: {
73
+ type: 'integer',
74
+ },
75
+ filter: {
76
+ type: 'string',
77
+ },
78
+ },
79
+ required: [],
80
+ additionalProperties: false,
81
+ };
82
+ const generatedInput = (0, GenerateInput_1.generateInput)({
83
+ operationNameCamelCase,
84
+ parameters,
85
+ });
86
+ const generatedInputFile = yield TE.getOrElse((error) => {
87
+ throw new Error('Should have been right');
88
+ })(generatedInput)();
89
+ const expected = `export interface GetPostInput {
90
+ id?: number;
91
+ filter?: string;
92
+ }
93
+ `;
94
+ expect(generatedInputFile).toEqual(expected);
95
+ }));
96
+ it('it should generate input.ts file contents when given JSON schema body params', () => __awaiter(void 0, void 0, void 0, function* () {
97
+ const operationNameCamelCase = 'createPost';
98
+ const parameters = {
99
+ type: 'object',
100
+ required: ['id', 'userId', 'title', 'body'],
101
+ properties: {
102
+ id: {
103
+ type: 'integer',
104
+ },
105
+ userId: {
106
+ type: 'integer',
107
+ },
108
+ title: {
109
+ type: 'string',
110
+ },
111
+ body: {
112
+ type: 'string',
113
+ },
114
+ },
115
+ additionalProperties: false,
116
+ };
117
+ const generatedInput = (0, GenerateInput_1.generateInput)({
118
+ operationNameCamelCase,
119
+ parameters,
120
+ });
121
+ const generatedInputFile = yield TE.getOrElse((error) => {
122
+ throw new Error('Should have been right');
123
+ })(generatedInput)();
124
+ const expected = `export interface CreatePostInput {
125
+ id: number;
126
+ userId: number;
127
+ title: string;
128
+ body: string;
129
+ }
130
+ `;
131
+ expect(generatedInputFile).toEqual(expected);
132
+ }));
133
+ });
@@ -0,0 +1,4 @@
1
+ import * as TE from 'fp-ts/TaskEither';
2
+ import { Path } from '../../OpenApiTypeDescriptors';
3
+ export declare const processInput: (endpoint: Path) => TE.TaskEither<Error, string>;
4
+ //# sourceMappingURL=ProcessInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProcessInput.d.ts","sourceRoot":"","sources":["../../../src/connector/input/ProcessInput.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAIvC,OAAO,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;AA2DpD,eAAO,MAAM,YAAY,aAAc,IAAI,KAAG,GAAG,UAAU,CAAC,KAAK,EAAE,MAAM,CAMxE,CAAC"}
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.processInput = void 0;
27
+ const lodash_1 = require("lodash");
28
+ const O = __importStar(require("fp-ts/Option"));
29
+ const GenerateInput_1 = require("./GenerateInput");
30
+ const TransformInput_1 = require("./TransformInput");
31
+ const mergeRequired = (params, body) => {
32
+ if ((0, lodash_1.isArray)(body.required) && (0, lodash_1.isArray)(params.required)) {
33
+ return [...body.required, ...params.required];
34
+ }
35
+ return [];
36
+ };
37
+ const mergeParamsAndBody = (params, body) => ({
38
+ type: 'object',
39
+ properties: Object.assign(Object.assign({}, body.properties), params.properties),
40
+ required: mergeRequired(params, body),
41
+ additionalProperties: false,
42
+ });
43
+ const getApplicationJsonMediaType = (content) => {
44
+ // TODO: we should support any value here, but there may also be more than 1 media type so we need to iterate through
45
+ // and combine all the schemas within into a single set of inputs
46
+ const mediaTypeApplicationJson = Object.keys(content).find((mediaType) => /^application\/.*json$/.test(mediaType));
47
+ if (mediaTypeApplicationJson) {
48
+ return content[mediaTypeApplicationJson];
49
+ }
50
+ const mediaTypes = Object.keys(content);
51
+ throw new Error(`Unsupported media type: ${mediaTypes}`);
52
+ };
53
+ const extractInput = (endpoint) => {
54
+ const parameters = O.toNullable(endpoint.parameters);
55
+ const requestBody = O.toNullable(endpoint.requestBody);
56
+ if (parameters && !requestBody) {
57
+ return (0, TransformInput_1.transformInput)(parameters);
58
+ }
59
+ if (requestBody && !parameters) {
60
+ return getApplicationJsonMediaType(requestBody.content).schema;
61
+ }
62
+ if (requestBody && parameters) {
63
+ const params = (0, TransformInput_1.transformInput)(parameters);
64
+ const body = getApplicationJsonMediaType(requestBody.content).schema;
65
+ return mergeParamsAndBody(params, body);
66
+ }
67
+ return {
68
+ type: 'object',
69
+ properties: {},
70
+ required: [],
71
+ additionalProperties: false,
72
+ };
73
+ };
74
+ const processInput = (endpoint) => {
75
+ const input = extractInput(endpoint);
76
+ return (0, GenerateInput_1.generateInput)({
77
+ operationNameCamelCase: endpoint.operationId,
78
+ parameters: input,
79
+ });
80
+ };
81
+ exports.processInput = processInput;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ProcessInput.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProcessInput.test.d.ts","sourceRoot":"","sources":["../../../src/connector/input/ProcessInput.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,227 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ const TE = __importStar(require("fp-ts/TaskEither"));
36
+ const O = __importStar(require("fp-ts/Option"));
37
+ const ProcessInput_1 = require("./ProcessInput");
38
+ describe('Input: ProcessInput', () => {
39
+ it('it should process an endpoint with path and query string parameters and generate input.ts file contents', () => __awaiter(void 0, void 0, void 0, function* () {
40
+ const endpoint = {
41
+ operationId: 'getPost',
42
+ description: '',
43
+ tags: [],
44
+ parameters: O.some([
45
+ {
46
+ name: 'id',
47
+ in: 'path',
48
+ required: true,
49
+ description: 'The user id.',
50
+ schema: {
51
+ type: 'integer',
52
+ format: O.some('int64'),
53
+ },
54
+ },
55
+ ]),
56
+ requestBody: O.none,
57
+ };
58
+ const processedInput = (0, ProcessInput_1.processInput)(endpoint);
59
+ const generatedInputFile = yield TE.getOrElse((error) => {
60
+ throw new Error('Should have been right');
61
+ })(processedInput)();
62
+ const expectedInputFile = `export interface GetPostInput {
63
+ /**
64
+ * @description The user id.
65
+ */
66
+ id: number;
67
+ }
68
+ `;
69
+ expect(generatedInputFile).toEqual(expectedInputFile);
70
+ }));
71
+ it('it should process an endpoint with body parameters and generate input.ts file contents', () => __awaiter(void 0, void 0, void 0, function* () {
72
+ const endpoint = {
73
+ operationId: 'createPost',
74
+ description: 'Create a new post',
75
+ tags: [],
76
+ parameters: O.none,
77
+ requestBody: O.some({
78
+ content: {
79
+ 'application/json': {
80
+ schema: {
81
+ type: 'object',
82
+ required: ['id', 'userId', 'title', 'body'],
83
+ properties: {
84
+ id: {
85
+ type: 'integer',
86
+ },
87
+ userId: {
88
+ type: 'integer',
89
+ },
90
+ title: {
91
+ type: 'string',
92
+ },
93
+ body: {
94
+ type: 'string',
95
+ },
96
+ },
97
+ additionalProperties: false,
98
+ },
99
+ },
100
+ },
101
+ required: true,
102
+ }),
103
+ };
104
+ const processedInput = (0, ProcessInput_1.processInput)(endpoint);
105
+ const generatedInputFile = yield TE.getOrElse((error) => {
106
+ throw new Error('Should have been right');
107
+ })(processedInput)();
108
+ const expectedInputFile = `export interface CreatePostInput {
109
+ id: number;
110
+ userId: number;
111
+ title: string;
112
+ body: string;
113
+ }
114
+ `;
115
+ expect(generatedInputFile).toEqual(expectedInputFile);
116
+ }));
117
+ it('it should process an endpoint with path, query string and body parameters and generate input.ts file contents', () => __awaiter(void 0, void 0, void 0, function* () {
118
+ const endpoint = {
119
+ operationId: 'getPost',
120
+ description: '',
121
+ tags: [],
122
+ parameters: O.some([
123
+ {
124
+ name: 'id',
125
+ in: 'path',
126
+ required: true,
127
+ description: 'The user id.',
128
+ schema: {
129
+ type: 'integer',
130
+ format: O.some('int64'),
131
+ },
132
+ },
133
+ ]),
134
+ requestBody: O.some({
135
+ content: {
136
+ 'application/json': {
137
+ schema: {
138
+ type: 'object',
139
+ required: ['id', 'userId', 'title', 'body'],
140
+ properties: {
141
+ userId: {
142
+ type: 'integer',
143
+ },
144
+ title: {
145
+ type: 'string',
146
+ },
147
+ body: {
148
+ type: 'string',
149
+ },
150
+ },
151
+ additionalProperties: false,
152
+ },
153
+ },
154
+ },
155
+ required: true,
156
+ }),
157
+ };
158
+ const processedInput = (0, ProcessInput_1.processInput)(endpoint);
159
+ const generatedInputFile = yield TE.getOrElse((error) => {
160
+ throw new Error('Should have been right');
161
+ })(processedInput)();
162
+ const expectedInputFile = `export interface GetPostInput {
163
+ userId: number;
164
+ title: string;
165
+ body: string;
166
+ /**
167
+ * @description The user id.
168
+ */
169
+ id: number;
170
+ }
171
+ `;
172
+ expect(generatedInputFile).toEqual(expectedInputFile);
173
+ }));
174
+ it('it should process an endpoint with no parameters and generate empty input.ts file contents', () => __awaiter(void 0, void 0, void 0, function* () {
175
+ const endpoint = {
176
+ operationId: 'getPosts',
177
+ description: '',
178
+ tags: [],
179
+ parameters: O.none,
180
+ requestBody: O.none,
181
+ };
182
+ const processedInput = (0, ProcessInput_1.processInput)(endpoint);
183
+ const generatedInputFile = yield TE.getOrElse((error) => {
184
+ throw new Error('Should have been right');
185
+ })(processedInput)();
186
+ const expectedInputFile = `export interface GetPostsInput {}
187
+ `;
188
+ expect(generatedInputFile).toEqual(expectedInputFile);
189
+ }));
190
+ it('it should throw an exception when finding an unsupported media type', () => __awaiter(void 0, void 0, void 0, function* () {
191
+ const endpoint = {
192
+ operationId: 'createPost',
193
+ description: '',
194
+ tags: [],
195
+ parameters: O.none,
196
+ requestBody: O.some({
197
+ content: {
198
+ 'unsupported-media-type': {
199
+ schema: {
200
+ type: 'object',
201
+ required: ['id', 'userId', 'title', 'body'],
202
+ properties: {
203
+ id: {
204
+ type: 'integer',
205
+ },
206
+ userId: {
207
+ type: 'integer',
208
+ },
209
+ title: {
210
+ type: 'string',
211
+ },
212
+ body: {
213
+ type: 'string',
214
+ },
215
+ },
216
+ additionalProperties: false,
217
+ },
218
+ },
219
+ },
220
+ required: true,
221
+ }),
222
+ };
223
+ yield expect(() => __awaiter(void 0, void 0, void 0, function* () {
224
+ (0, ProcessInput_1.processInput)(endpoint);
225
+ })).rejects.toThrow('Unsupported media type: unsupported-media-type');
226
+ }));
227
+ });
@@ -0,0 +1,4 @@
1
+ import { JSONSchema4 } from 'json-schema';
2
+ import { Parameter } from '../../OpenApiTypeDescriptors';
3
+ export declare const transformInput: (parameters: Parameter[]) => JSONSchema4;
4
+ //# sourceMappingURL=TransformInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TransformInput.d.ts","sourceRoot":"","sources":["../../../src/connector/input/TransformInput.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG1C,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAEzD,eAAO,MAAM,cAAc,eAAgB,SAAS,EAAE,KAAG,WA4BxD,CAAC"}
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.transformInput = void 0;
27
+ const openapi_schema_to_json_schema_1 = require("@openapi-contrib/openapi-schema-to-json-schema");
28
+ const O = __importStar(require("fp-ts/Option"));
29
+ const transformInput = (parameters) => {
30
+ const transformedParameters = {};
31
+ const requiredParameters = [];
32
+ parameters.forEach((parameter) => {
33
+ const paramterWithJsdocAnnotation = {
34
+ name: parameter.name,
35
+ description: `@description ${parameter.description}`,
36
+ required: parameter.required,
37
+ schema: {
38
+ type: parameter.schema.type,
39
+ format: O.toNullable(parameter.schema.format) || undefined,
40
+ },
41
+ };
42
+ transformedParameters[parameter.name] = (0, openapi_schema_to_json_schema_1.fromParameter)(paramterWithJsdocAnnotation);
43
+ if (parameter.required === true) {
44
+ requiredParameters.push(parameter.name);
45
+ }
46
+ });
47
+ return {
48
+ type: 'object',
49
+ properties: Object.assign({}, transformedParameters),
50
+ required: [...requiredParameters],
51
+ additionalProperties: false,
52
+ };
53
+ };
54
+ exports.transformInput = transformInput;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=TransformInput.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TransformInput.test.d.ts","sourceRoot":"","sources":["../../../src/connector/input/TransformInput.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ const O = __importStar(require("fp-ts/Option"));
27
+ const TransformInput_1 = require("./TransformInput");
28
+ describe('Input: TransformInput', () => {
29
+ it('it should transform open api spec path and query parameters into JSON schema', () => {
30
+ const openApiSpecParameters = [
31
+ {
32
+ name: 'id',
33
+ in: 'path',
34
+ required: true,
35
+ description: 'The user id.',
36
+ schema: {
37
+ type: 'integer',
38
+ format: O.some('int64'),
39
+ },
40
+ },
41
+ {
42
+ name: 'filter',
43
+ in: 'query',
44
+ required: false,
45
+ description: 'The type to filter on.',
46
+ schema: {
47
+ type: 'string',
48
+ format: O.none,
49
+ },
50
+ },
51
+ ];
52
+ const generatedJsonSchema = (0, TransformInput_1.transformInput)(openApiSpecParameters);
53
+ const expectedJsonSchema = {
54
+ type: 'object',
55
+ properties: {
56
+ id: {
57
+ type: 'integer',
58
+ $schema: 'http://json-schema.org/draft-04/schema#',
59
+ description: '@description The user id.',
60
+ format: 'int64',
61
+ maximum: 9223372036854776000,
62
+ minimum: -9223372036854776000,
63
+ },
64
+ filter: {
65
+ type: 'string',
66
+ $schema: 'http://json-schema.org/draft-04/schema#',
67
+ description: '@description The type to filter on.',
68
+ },
69
+ },
70
+ required: ['id'],
71
+ additionalProperties: false,
72
+ };
73
+ expect(generatedJsonSchema).toEqual(expectedJsonSchema);
74
+ });
75
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trayio/tray-openapi",
3
- "version": "2.4.0",
3
+ "version": "2.5.0",
4
4
  "description": "Creating CDK Projects from OpenAPI 3.0 Schemas",
5
5
  "exports": {
6
6
  "./*": "./dist/*.js"
@@ -20,5 +20,9 @@
20
20
  },
21
21
  "files": [
22
22
  "/dist"
23
- ]
23
+ ],
24
+ "dependencies": {
25
+ "@openapi-contrib/openapi-schema-to-json-schema": "5.1.0",
26
+ "json-schema-to-typescript": "13.1.1"
27
+ }
24
28
  }