@trayio/tray-openapi 2.10.0 → 2.11.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.
- package/dist/OpenApiSchemaImporter.d.ts +2 -1
- package/dist/OpenApiSchemaImporter.d.ts.map +1 -1
- package/dist/OpenApiSchemaImporter.js +23 -4
- package/dist/OpenApiSchemaImporter.test.js +20 -10
- package/dist/OpenApiSchemaTransformer.d.ts +9 -0
- package/dist/OpenApiSchemaTransformer.d.ts.map +1 -0
- package/dist/OpenApiSchemaTransformer.js +68 -0
- package/dist/OpenApiSchemaTransformer.test.d.ts +2 -0
- package/dist/OpenApiSchemaTransformer.test.d.ts.map +1 -0
- package/dist/OpenApiSchemaTransformer.test.js +118 -0
- package/dist/OpenApiTypeDescriptors.d.ts +38 -6
- package/dist/OpenApiTypeDescriptors.d.ts.map +1 -1
- package/dist/OpenApiTypeDescriptors.js +4 -11
- package/dist/file-generators/types/GenerateInputSchema.d.ts +2 -1
- package/dist/file-generators/types/GenerateInputSchema.d.ts.map +1 -1
- package/dist/file-generators/types/GenerateInputSchema.js +22 -27
- package/dist/file-generators/types/GenerateInputSchema.test.js +54 -9
- package/dist/file-generators/types/GenerateInputType.test.js +38 -13
- package/dist/file-generators/types/GenerateOutput.d.ts.map +1 -1
- package/dist/file-generators/types/GenerateOutput.js +1 -4
- package/dist/test-openapi-spec.json +160 -0
- package/package.json +1 -1
- package/dist/single-get-openapi.json +0 -78
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import * as TE from 'fp-ts/TaskEither';
|
|
2
2
|
import { FileStorage } from '@trayio/commons/file/File';
|
|
3
3
|
import { Generator } from '@trayio/generator/generator/Generator';
|
|
4
|
+
import { BuildConnectorResponse } from './OpenApiTypeDescriptors';
|
|
4
5
|
export declare class OpenApiSchemaImporter {
|
|
5
6
|
private generator;
|
|
6
7
|
private fileStorage;
|
|
7
8
|
constructor(generator: Generator, fileStorage: FileStorage);
|
|
8
|
-
buildConnector(openApiSpecPath: string, connectorName: string): TE.TaskEither<Error,
|
|
9
|
+
buildConnector(openApiSpecPath: string, connectorName: string): TE.TaskEither<Error, BuildConnectorResponse>;
|
|
9
10
|
private generateOperationFromPath;
|
|
10
11
|
private decodeOperation;
|
|
11
12
|
private getOpenApiSpec;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OpenApiSchemaImporter.d.ts","sourceRoot":"","sources":["../src/OpenApiSchemaImporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AASvC,OAAO,EAAQ,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,uCAAuC,CAAC;
|
|
1
|
+
{"version":3,"file":"OpenApiSchemaImporter.d.ts","sourceRoot":"","sources":["../src/OpenApiSchemaImporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AASvC,OAAO,EAAQ,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,uCAAuC,CAAC;AAGlE,OAAO,EAEN,sBAAsB,EAMtB,MAAM,0BAA0B,CAAC;AAalC,qBAAa,qBAAqB;IACrB,OAAO,CAAC,SAAS;IAAa,OAAO,CAAC,WAAW;gBAAzC,SAAS,EAAE,SAAS,EAAU,WAAW,EAAE,WAAW;IAE1E,cAAc,CACb,eAAe,EAAE,MAAM,EACvB,aAAa,EAAE,MAAM,GACnB,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,sBAAsB,CAAC;IAoD/C,OAAO,CAAC,yBAAyB;IAyDjC,OAAO,CAAC,eAAe;IAgBvB,OAAO,CAAC,cAAc;IAoCtB,OAAO,CAAC,oCAAoC;IAgF5C,OAAO,CAAC,0BAA0B;IAwBlC,OAAO,CAAC,0BAA0B;CAclC"}
|
|
@@ -42,6 +42,7 @@ const GenerateInputTypes_1 = require("./file-generators/types/GenerateInputTypes
|
|
|
42
42
|
const GenerateHandlerTest_1 = require("./file-generators/GenerateHandlerTest");
|
|
43
43
|
const GenerateOperationJson_1 = require("./file-generators/GenerateOperationJson");
|
|
44
44
|
const GenerateInputSchema_1 = require("./file-generators/types/GenerateInputSchema");
|
|
45
|
+
const OpenApiSchemaTransformer_1 = require("./OpenApiSchemaTransformer");
|
|
45
46
|
class OpenApiSchemaImporter {
|
|
46
47
|
constructor(generator, fileStorage) {
|
|
47
48
|
this.generator = generator;
|
|
@@ -59,10 +60,28 @@ class OpenApiSchemaImporter {
|
|
|
59
60
|
path: openApiSpec.paths[path][route],
|
|
60
61
|
})),
|
|
61
62
|
})));
|
|
62
|
-
}), TE.chain(({ openApiSpec, connectorPath, paths }) => (0, Array_1.traverse)(TE.ApplicativeSeq)((path) => this.generateOperationFromPath(path, connectorPath, openApiSpec.servers[0].url, connectorName))(paths)), TE.map(() =>
|
|
63
|
+
}), TE.chain(({ openApiSpec, connectorPath, paths }) => (0, Array_1.traverse)(TE.ApplicativeSeq)((path) => this.generateOperationFromPath(path, connectorPath, openApiSpec.servers[0].url, connectorName))(paths)), TE.map((operation) => {
|
|
64
|
+
const flatOperations = operation.flat();
|
|
65
|
+
const buildConnectorResponse = flatOperations.reduce((acc, curr) => {
|
|
66
|
+
if (curr.tag === 'error') {
|
|
67
|
+
return Object.assign(Object.assign({}, acc), { errors: [...acc.errors, curr] });
|
|
68
|
+
}
|
|
69
|
+
return Object.assign(Object.assign({}, acc), { successes: [...acc.successes, curr] });
|
|
70
|
+
}, { successes: [], errors: [] });
|
|
71
|
+
return buildConnectorResponse;
|
|
72
|
+
}));
|
|
63
73
|
}
|
|
64
74
|
generateOperationFromPath(path, connectorPath, baseUrl, connectorName) {
|
|
65
|
-
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.
|
|
75
|
+
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(() => ({
|
|
76
|
+
tag: 'success',
|
|
77
|
+
httpMethod: route.method,
|
|
78
|
+
path: path.path,
|
|
79
|
+
})), TE.orElseW((error) => TE.right({
|
|
80
|
+
tag: 'error',
|
|
81
|
+
httpMethod: route.method,
|
|
82
|
+
path: path.path,
|
|
83
|
+
errorMessage: error.message,
|
|
84
|
+
}))))(path.routes));
|
|
66
85
|
}
|
|
67
86
|
decodeOperation(path, httpPath, method) {
|
|
68
87
|
return (0, function_1.pipe)(TE.fromEither(OpenApiCodecs_1.pathCodec.decode(path)), TE.mapLeft((error) => new Error(`Failed to decode httpPath: ${httpPath} and method: ${method} : ${error}`)));
|
|
@@ -72,7 +91,7 @@ class OpenApiSchemaImporter {
|
|
|
72
91
|
const resolver = new json_ref_resolver_1.Resolver({});
|
|
73
92
|
const resolvedOpenApiSpec = resolver.resolve(openApiSpec, {});
|
|
74
93
|
return resolvedOpenApiSpec;
|
|
75
|
-
}, (reason) => new Error(`Failed to resolve references in schema: ${reason}`))), TE.chain((openApiSpec) => TE.
|
|
94
|
+
}, (reason) => new Error(`Failed to resolve references in schema: ${reason}`))), TE.chain((openApiSpec) => TE.fromEither((0, OpenApiSchemaTransformer_1.mergePathLevelParamsIntoHttpMethod)(openApiSpec.result))));
|
|
76
95
|
}
|
|
77
96
|
generateHandlerFilesAndOperationJson(method, path, operationPath, baseUrl, httpPath, connectorName, input, output) {
|
|
78
97
|
const writeFile = (content, fileName) => this.fileStorage.write({
|
|
@@ -110,7 +129,7 @@ class OpenApiSchemaImporter {
|
|
|
110
129
|
connectorNameKebabCase: (0, lodash_1.kebabCase)(connectorName),
|
|
111
130
|
connectorNamePascalCase: StringExtensions_1.StringExtensions.pascalCase(connectorName),
|
|
112
131
|
connectorNameCamelCase: (0, lodash_1.camelCase)(connectorName),
|
|
113
|
-
}), TE.chain((parameters) => this.generator.generate(`${__dirname}/templates/connector-template.zip`,
|
|
132
|
+
}), 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}`)));
|
|
114
133
|
}
|
|
115
134
|
generateOperationDirectory(connectorPath, operationName) {
|
|
116
135
|
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)}`));
|
|
@@ -35,41 +35,51 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
35
35
|
const NodeFsGenerator_1 = require("@trayio/generator/generator/NodeFsGenerator");
|
|
36
36
|
const FakeFileStorage_1 = require("@trayio/commons/file/FakeFileStorage");
|
|
37
37
|
const stream_1 = require("stream");
|
|
38
|
+
const E = __importStar(require("fp-ts/Either"));
|
|
38
39
|
const fs = __importStar(require("fs-extra"));
|
|
39
40
|
const OpenApiSchemaImporter_1 = require("./OpenApiSchemaImporter");
|
|
40
|
-
const openApiSpec = __importStar(require("./
|
|
41
|
+
const openApiSpec = __importStar(require("./test-openapi-spec.json"));
|
|
41
42
|
describe('openApiSchemaImporter', () => {
|
|
42
43
|
const generator = new NodeFsGenerator_1.NodeFsGenerator();
|
|
43
44
|
const fileStorage = new FakeFileStorage_1.FakeFileStorage();
|
|
44
45
|
const openApiSchemaImporter = new OpenApiSchemaImporter_1.OpenApiSchemaImporter(generator, fileStorage);
|
|
45
46
|
let result;
|
|
47
|
+
const spec = 'test-openapi-spec.json';
|
|
46
48
|
beforeAll(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
47
49
|
fileStorage.write({
|
|
48
|
-
key: `${__dirname}
|
|
49
|
-
metadata: { name:
|
|
50
|
+
key: `${__dirname}/${spec}`,
|
|
51
|
+
metadata: { name: spec },
|
|
50
52
|
content: stream_1.Readable.from(Buffer.from(JSON.stringify(openApiSpec))),
|
|
51
53
|
});
|
|
52
|
-
result = yield openApiSchemaImporter.buildConnector(`${__dirname}
|
|
54
|
+
result = yield openApiSchemaImporter.buildConnector(`${__dirname}/${spec}`, 'testConnector')();
|
|
53
55
|
}));
|
|
54
56
|
afterAll(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
55
57
|
yield fs.rm(`${process.cwd()}/test/`, { recursive: true, force: true });
|
|
56
58
|
}));
|
|
57
59
|
it('should import successfully', () => {
|
|
58
|
-
|
|
60
|
+
const buildConnectorResponse = E.getOrElse((error) => {
|
|
61
|
+
console.error(error);
|
|
62
|
+
throw new Error('Should have been right');
|
|
63
|
+
})(result);
|
|
64
|
+
expect(buildConnectorResponse.successes.length).toEqual(1);
|
|
65
|
+
expect(buildConnectorResponse.errors.length).toEqual(1);
|
|
59
66
|
});
|
|
60
67
|
it('should generate a operation handler', () => {
|
|
61
|
-
expect(fileStorage.files.has(`/test
|
|
68
|
+
expect(fileStorage.files.has(`/test-connector/src/get-post/handler.ts`)).toEqual(true);
|
|
62
69
|
});
|
|
63
70
|
it('should generate an operation handler test', () => {
|
|
64
|
-
expect(fileStorage.files.has(`/test
|
|
71
|
+
expect(fileStorage.files.has(`/test-connector/src/get-post/handler.test.ts`)).toEqual(true);
|
|
65
72
|
});
|
|
66
73
|
it('should generate an operation.json', () => {
|
|
67
|
-
expect(fileStorage.files.has(`/test
|
|
74
|
+
expect(fileStorage.files.has(`/test-connector/src/get-post/operation.json`)).toEqual(true);
|
|
68
75
|
});
|
|
69
76
|
it('should generate an output.ts', () => {
|
|
70
|
-
expect(fileStorage.files.has(`/test
|
|
77
|
+
expect(fileStorage.files.has(`/test-connector/src/get-post/output.ts`)).toEqual(true);
|
|
71
78
|
});
|
|
72
79
|
it('should generate a operation directory', () => {
|
|
73
|
-
expect(fileStorage.files.has(`/test
|
|
80
|
+
expect(fileStorage.files.has(`/test-connector/src/get-post`)).toEqual(true);
|
|
81
|
+
});
|
|
82
|
+
it('should not generate a operation directory when failing to decode', () => {
|
|
83
|
+
expect(fileStorage.files.has(`/test-connector/src/update-post`)).toEqual(false);
|
|
74
84
|
});
|
|
75
85
|
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as E from 'fp-ts/Either';
|
|
2
|
+
import { BaseOpenApiSpec } from './OpenApiTypeDescriptors';
|
|
3
|
+
export declare const isObject: (value: unknown) => value is Record<string, unknown>;
|
|
4
|
+
export declare const isObjectWithParameters: (value: unknown) => value is Record<string, unknown> & {
|
|
5
|
+
parameters: unknown[];
|
|
6
|
+
};
|
|
7
|
+
export declare const getMergedParameters: (pathValue: Record<string, unknown>, httpMethodValue: Record<string, unknown>) => unknown[];
|
|
8
|
+
export declare const mergePathLevelParamsIntoHttpMethod: (openApiSpec: BaseOpenApiSpec) => E.Either<Error, BaseOpenApiSpec>;
|
|
9
|
+
//# sourceMappingURL=OpenApiSchemaTransformer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpenApiSchemaTransformer.d.ts","sourceRoot":"","sources":["../src/OpenApiSchemaTransformer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAE3D,eAAO,MAAM,QAAQ,UAAW,OAAO,qCACK,CAAC;AAE7C,eAAO,MAAM,sBAAsB,UAC3B,OAAO;gBACqC,OAAO,EAAE;CACpB,CAAC;AAE1C,eAAO,MAAM,mBAAmB,cACpB,OAAO,MAAM,EAAE,OAAO,CAAC,mBACjB,OAAO,MAAM,EAAE,OAAO,CAAC,KACtC,OAAO,EAcT,CAAC;AAEF,eAAO,MAAM,kCAAkC,gBACjC,eAAe,KAC1B,EAAE,MAAM,CAAC,KAAK,EAAE,eAAe,CAkCjC,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
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.mergePathLevelParamsIntoHttpMethod = exports.getMergedParameters = exports.isObjectWithParameters = exports.isObject = void 0;
|
|
27
|
+
const E = __importStar(require("fp-ts/Either"));
|
|
28
|
+
const isObject = (value) => typeof value === 'object' && value !== null;
|
|
29
|
+
exports.isObject = isObject;
|
|
30
|
+
const isObjectWithParameters = (value) => (0, exports.isObject)(value) && 'parameters' in value;
|
|
31
|
+
exports.isObjectWithParameters = isObjectWithParameters;
|
|
32
|
+
const getMergedParameters = (pathValue, httpMethodValue) => {
|
|
33
|
+
if (!Array.isArray(pathValue.parameters)) {
|
|
34
|
+
throw new Error('Path parameters is not an array');
|
|
35
|
+
}
|
|
36
|
+
// if the method contains existing parameters, we merge them with the path parameters
|
|
37
|
+
if ('parameters' in httpMethodValue &&
|
|
38
|
+
Array.isArray(httpMethodValue.parameters)) {
|
|
39
|
+
return [...httpMethodValue.parameters, ...pathValue.parameters];
|
|
40
|
+
}
|
|
41
|
+
return pathValue.parameters;
|
|
42
|
+
};
|
|
43
|
+
exports.getMergedParameters = getMergedParameters;
|
|
44
|
+
const mergePathLevelParamsIntoHttpMethod = (openApiSpec) => {
|
|
45
|
+
const paths = Object.entries(openApiSpec.paths).reduce((pathAcc, [pathName, pathValue]) => {
|
|
46
|
+
// if the path doesn't contain top level params, we just return it
|
|
47
|
+
if (!(0, exports.isObjectWithParameters)(pathValue)) {
|
|
48
|
+
pathAcc[pathName] = pathValue;
|
|
49
|
+
return pathAcc;
|
|
50
|
+
}
|
|
51
|
+
const updatedPathValue = Object.entries(pathValue).reduce((methodAcc, [httpMethodName, httpMethodValue]) => {
|
|
52
|
+
if (!(0, exports.isObject)(httpMethodValue)) {
|
|
53
|
+
throw new Error('Http method value is not an object');
|
|
54
|
+
}
|
|
55
|
+
// we skip adding the parameters object to the path object
|
|
56
|
+
if (httpMethodName === 'parameters') {
|
|
57
|
+
return methodAcc;
|
|
58
|
+
}
|
|
59
|
+
const parameters = (0, exports.getMergedParameters)(pathValue, httpMethodValue);
|
|
60
|
+
methodAcc[httpMethodName] = Object.assign(Object.assign({}, httpMethodValue), { parameters });
|
|
61
|
+
return methodAcc;
|
|
62
|
+
}, {});
|
|
63
|
+
pathAcc[pathName] = updatedPathValue;
|
|
64
|
+
return pathAcc;
|
|
65
|
+
}, {});
|
|
66
|
+
return E.right(Object.assign(Object.assign({}, openApiSpec), { paths }));
|
|
67
|
+
};
|
|
68
|
+
exports.mergePathLevelParamsIntoHttpMethod = mergePathLevelParamsIntoHttpMethod;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpenApiSchemaTransformer.test.d.ts","sourceRoot":"","sources":["../src/OpenApiSchemaTransformer.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,118 @@
|
|
|
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 E = __importStar(require("fp-ts/Either"));
|
|
27
|
+
const OpenApiSchemaTransformer_1 = require("./OpenApiSchemaTransformer");
|
|
28
|
+
describe('mergePathLevelParamsIntoHttpMethod', () => {
|
|
29
|
+
it('should merge path level parameters into HTTP methods', () => {
|
|
30
|
+
const openApiSpec = {
|
|
31
|
+
openapi: '3.0.0',
|
|
32
|
+
info: {
|
|
33
|
+
version: '1.0.0',
|
|
34
|
+
title: 'JSON Placeholder API',
|
|
35
|
+
description: 'See https://jsonplaceholder.typicode.com/',
|
|
36
|
+
},
|
|
37
|
+
servers: [
|
|
38
|
+
{
|
|
39
|
+
url: 'https://jsonplaceholder.typicode.com',
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
paths: {
|
|
43
|
+
'/path': {
|
|
44
|
+
parameters: [{ name: 'param1', in: 'query', required: false }],
|
|
45
|
+
get: {
|
|
46
|
+
parameters: [{ name: 'param2', in: 'query', required: true }],
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
const result = (0, OpenApiSchemaTransformer_1.mergePathLevelParamsIntoHttpMethod)(openApiSpec);
|
|
52
|
+
E.fold((error) => {
|
|
53
|
+
throw new Error(`Test failed with error: ${error.message}`);
|
|
54
|
+
}, (updatedOpenApiSpec) => {
|
|
55
|
+
expect(updatedOpenApiSpec.paths['/path'].get.parameters).toEqual([
|
|
56
|
+
{ name: 'param2', in: 'query', required: true },
|
|
57
|
+
{ name: 'param1', in: 'query', required: false },
|
|
58
|
+
]);
|
|
59
|
+
})(result);
|
|
60
|
+
});
|
|
61
|
+
it('should return the original spec if no top level parameters', () => {
|
|
62
|
+
const openApiSpec = {
|
|
63
|
+
openapi: '3.0.0',
|
|
64
|
+
info: {
|
|
65
|
+
version: '1.0.0',
|
|
66
|
+
title: 'JSON Placeholder API',
|
|
67
|
+
description: 'See https://jsonplaceholder.typicode.com/',
|
|
68
|
+
},
|
|
69
|
+
servers: [
|
|
70
|
+
{
|
|
71
|
+
url: 'https://jsonplaceholder.typicode.com',
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
paths: {
|
|
75
|
+
'/path': {
|
|
76
|
+
get: {
|
|
77
|
+
parameters: [{ name: 'param2', in: 'query', required: true }],
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
const result = (0, OpenApiSchemaTransformer_1.mergePathLevelParamsIntoHttpMethod)(openApiSpec);
|
|
83
|
+
E.fold((error) => {
|
|
84
|
+
throw new Error(`Test failed with error: ${error.message}`);
|
|
85
|
+
}, (updatedOpenApiSpec) => {
|
|
86
|
+
expect(updatedOpenApiSpec).toEqual(openApiSpec);
|
|
87
|
+
})(result);
|
|
88
|
+
});
|
|
89
|
+
it('should add path level parameters into HTTP methods, if no method params already exist', () => {
|
|
90
|
+
const openApiSpec = {
|
|
91
|
+
openapi: '3.0.0',
|
|
92
|
+
info: {
|
|
93
|
+
version: '1.0.0',
|
|
94
|
+
title: 'JSON Placeholder API',
|
|
95
|
+
description: 'See https://jsonplaceholder.typicode.com/',
|
|
96
|
+
},
|
|
97
|
+
servers: [
|
|
98
|
+
{
|
|
99
|
+
url: 'https://jsonplaceholder.typicode.com',
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
paths: {
|
|
103
|
+
'/path': {
|
|
104
|
+
parameters: [{ name: 'param1', in: 'query', required: false }],
|
|
105
|
+
get: {},
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
const result = (0, OpenApiSchemaTransformer_1.mergePathLevelParamsIntoHttpMethod)(openApiSpec);
|
|
110
|
+
E.fold((error) => {
|
|
111
|
+
throw new Error(`Test failed with error: ${error.message}`);
|
|
112
|
+
}, (updatedOpenApiSpec) => {
|
|
113
|
+
expect(updatedOpenApiSpec.paths['/path'].get.parameters).toEqual([
|
|
114
|
+
{ name: 'param1', in: 'query', required: false },
|
|
115
|
+
]);
|
|
116
|
+
})(result);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
import * as t from 'io-ts';
|
|
2
2
|
import * as O from 'fp-ts/Option';
|
|
3
|
+
export type FlatPath = {
|
|
4
|
+
path: string;
|
|
5
|
+
routes: {
|
|
6
|
+
method: OpenApiHttpMethod;
|
|
7
|
+
path: unknown;
|
|
8
|
+
}[];
|
|
9
|
+
};
|
|
10
|
+
export type Server = {
|
|
11
|
+
url: string;
|
|
12
|
+
};
|
|
13
|
+
export type BaseOpenApiSpec = {
|
|
14
|
+
openapi: string;
|
|
15
|
+
info: {
|
|
16
|
+
version: string;
|
|
17
|
+
title: string;
|
|
18
|
+
description: string;
|
|
19
|
+
};
|
|
20
|
+
servers: Server[];
|
|
21
|
+
paths: Record<string, Record<string, unknown>>;
|
|
22
|
+
};
|
|
23
|
+
export type BaseOperation = {
|
|
24
|
+
httpMethod: OpenApiHttpMethod;
|
|
25
|
+
path: string;
|
|
26
|
+
};
|
|
27
|
+
export type OperationError = BaseOperation & {
|
|
28
|
+
tag: 'error';
|
|
29
|
+
errorMessage: string;
|
|
30
|
+
};
|
|
31
|
+
export type OperationSuccess = BaseOperation & {
|
|
32
|
+
tag: 'success';
|
|
33
|
+
};
|
|
34
|
+
export type Operation = OperationError | OperationSuccess;
|
|
35
|
+
export type BuildConnectorResponse = {
|
|
36
|
+
successes: OperationSuccess[];
|
|
37
|
+
errors: OperationError[];
|
|
38
|
+
};
|
|
3
39
|
export type Path = {
|
|
4
40
|
description: string;
|
|
5
41
|
tags: O.Option<string[]>;
|
|
@@ -12,12 +48,8 @@ export type Parameter = {
|
|
|
12
48
|
name: string;
|
|
13
49
|
in: string;
|
|
14
50
|
description: string;
|
|
15
|
-
required: boolean
|
|
16
|
-
schema:
|
|
17
|
-
type: string;
|
|
18
|
-
format: O.Option<string>;
|
|
19
|
-
items: O.Option<SchemaObject>;
|
|
20
|
-
};
|
|
51
|
+
required: O.Option<boolean>;
|
|
52
|
+
schema: SchemaObject;
|
|
21
53
|
};
|
|
22
54
|
export type RequestBody = {
|
|
23
55
|
content: Record<string, MediaTypeObject>;
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
1
|
+
{"version":3,"file":"OpenApiTypeDescriptors.d.ts","sourceRoot":"","sources":["../src/OpenApiTypeDescriptors.ts"],"names":[],"mappings":"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"}
|
|
@@ -27,7 +27,7 @@ exports.openApiSpecTypeDescriptor = exports.openApiSpecPathTypeDescriptor = expo
|
|
|
27
27
|
const t = __importStar(require("io-ts"));
|
|
28
28
|
const io_ts_types_1 = require("io-ts-types");
|
|
29
29
|
const TypeCodec_1 = require("@trayio/commons/codec/TypeCodec");
|
|
30
|
-
//
|
|
30
|
+
// Type Descriptors
|
|
31
31
|
const nonArraySchemaObjectType = t.keyof({
|
|
32
32
|
boolean: null,
|
|
33
33
|
object: null,
|
|
@@ -61,10 +61,7 @@ exports.schemaObjectTypeDescriptor = t.recursion('schemaObject', () => t.union([
|
|
|
61
61
|
arraySchemaObjectSchemaTypeDescriptor,
|
|
62
62
|
nonArraySchemaObjectSchemaTypeDescriptor,
|
|
63
63
|
]));
|
|
64
|
-
exports.schemaObjectTypeCodec = TypeCodec_1.TypeCodec.fromDescriptor(
|
|
65
|
-
arraySchemaObjectSchemaTypeDescriptor,
|
|
66
|
-
nonArraySchemaObjectSchemaTypeDescriptor,
|
|
67
|
-
])));
|
|
64
|
+
exports.schemaObjectTypeCodec = TypeCodec_1.TypeCodec.fromDescriptor(exports.schemaObjectTypeDescriptor);
|
|
68
65
|
const componentSchemaTypeDescriptor = t.type({
|
|
69
66
|
schemas: (0, io_ts_types_1.optionFromNullable)(t.record(t.string, exports.schemaObjectTypeDescriptor)),
|
|
70
67
|
});
|
|
@@ -82,12 +79,8 @@ exports.parameterSchemaTypeDescriptor = t.type({
|
|
|
82
79
|
name: t.string,
|
|
83
80
|
in: t.string,
|
|
84
81
|
description: t.string,
|
|
85
|
-
required: t.boolean,
|
|
86
|
-
schema:
|
|
87
|
-
type: t.string,
|
|
88
|
-
format: (0, io_ts_types_1.optionFromNullable)(t.string),
|
|
89
|
-
items: (0, io_ts_types_1.optionFromNullable)(exports.schemaObjectTypeDescriptor),
|
|
90
|
-
}),
|
|
82
|
+
required: (0, io_ts_types_1.optionFromNullable)(t.boolean),
|
|
83
|
+
schema: exports.schemaObjectTypeDescriptor,
|
|
91
84
|
});
|
|
92
85
|
exports.openApiSpecPathTypeDescriptor = t.type({
|
|
93
86
|
description: t.string,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as E from 'fp-ts/Either';
|
|
1
2
|
import { Path, SchemaObject } from '../../OpenApiTypeDescriptors';
|
|
2
|
-
export declare const generateInputSchema: (endpoint: Path) => SchemaObject
|
|
3
|
+
export declare const generateInputSchema: (endpoint: Path) => E.Either<Error, SchemaObject>;
|
|
3
4
|
//# sourceMappingURL=GenerateInputSchema.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GenerateInputSchema.d.ts","sourceRoot":"","sources":["../../../src/file-generators/types/GenerateInputSchema.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"GenerateInputSchema.d.ts","sourceRoot":"","sources":["../../../src/file-generators/types/GenerateInputSchema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAQlC,OAAO,EACN,IAAI,EAGJ,YAAY,EAEZ,MAAM,8BAA8B,CAAC;AAyItC,eAAO,MAAM,mBAAmB,aACrB,IAAI,KACZ,EAAE,MAAM,CAAC,KAAK,EAAE,YAAY,CAiC9B,CAAC"}
|
|
@@ -24,6 +24,8 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.generateInputSchema = void 0;
|
|
27
|
+
const E = __importStar(require("fp-ts/Either"));
|
|
28
|
+
const function_1 = require("fp-ts/function");
|
|
27
29
|
const lodash_1 = require("lodash");
|
|
28
30
|
const O = __importStar(require("fp-ts/Option"));
|
|
29
31
|
const openapi_schema_to_json_schema_1 = require("@openapi-contrib/openapi-schema-to-json-schema");
|
|
@@ -62,7 +64,7 @@ const transformInput = (parameters) => {
|
|
|
62
64
|
throw new Error('Failed to decode params');
|
|
63
65
|
}
|
|
64
66
|
transformedParameters[parameter.name] = decodedParam.right;
|
|
65
|
-
if (parameter.required === true) {
|
|
67
|
+
if (O.isSome(parameter.required) && parameter.required.value === true) {
|
|
66
68
|
requiredParameters.push(parameter.name);
|
|
67
69
|
}
|
|
68
70
|
});
|
|
@@ -85,49 +87,42 @@ const appendInPropertyToBody = (body) => O.fold(() => body, (properties) => {
|
|
|
85
87
|
const propsWithInBody = Object.keys(properties).reduce((acc, name) => (Object.assign(Object.assign({}, acc), { [name]: Object.assign(Object.assign({}, properties[name]), { in: O.some('body') }) })), {});
|
|
86
88
|
return Object.assign(Object.assign({}, body), { properties: O.some(propsWithInBody) });
|
|
87
89
|
})(body.properties);
|
|
90
|
+
const blankOutputSchema = () => ({
|
|
91
|
+
type: O.none,
|
|
92
|
+
properties: O.none,
|
|
93
|
+
required: O.none,
|
|
94
|
+
additionalProperties: O.some(false),
|
|
95
|
+
allOf: O.none,
|
|
96
|
+
anyOf: O.none,
|
|
97
|
+
oneOf: O.none,
|
|
98
|
+
not: O.none,
|
|
99
|
+
in: O.none,
|
|
100
|
+
});
|
|
88
101
|
const getApplicationJsonMediaType = (content) => {
|
|
102
|
+
if (!Object.keys(content).length)
|
|
103
|
+
return E.right({ schema: O.none });
|
|
89
104
|
// TODO: we should support any value here, but there may also be more than 1 media type so we need to iterate through
|
|
90
105
|
// and combine all the schemas within into a single set of inputs
|
|
91
106
|
const mediaTypeApplicationJson = Object.keys(content).find((mediaType) => /^application\/.*json$/.test(mediaType));
|
|
92
|
-
// TODO: fold here instead of getOrElse
|
|
93
107
|
if (mediaTypeApplicationJson) {
|
|
94
|
-
return
|
|
95
|
-
throw new Error('');
|
|
96
|
-
})(content[mediaTypeApplicationJson].schema);
|
|
108
|
+
return E.right(content[mediaTypeApplicationJson]);
|
|
97
109
|
}
|
|
98
110
|
const mediaTypes = Object.keys(content);
|
|
99
|
-
|
|
111
|
+
return E.left(new Error(`Unsupported media type: ${mediaTypes}`));
|
|
100
112
|
};
|
|
101
113
|
const generateInputSchema = (endpoint) => {
|
|
102
|
-
// TODO: use the encode method instead of this, or fold over the values
|
|
103
114
|
const parameters = O.toNullable(endpoint.parameters);
|
|
104
115
|
const requestBody = O.toNullable(endpoint.requestBody);
|
|
105
116
|
if (parameters && !requestBody) {
|
|
106
|
-
return transformInput(parameters);
|
|
117
|
+
return E.right(transformInput(parameters));
|
|
107
118
|
}
|
|
108
119
|
if (requestBody && !parameters) {
|
|
109
|
-
|
|
110
|
-
const body = getApplicationJsonMediaType(requestBody.content);
|
|
111
|
-
return appendInPropertyToBody(body);
|
|
112
|
-
// return getApplicationJsonMediaType(getContent(requestBody.content));
|
|
120
|
+
return (0, function_1.pipe)(getApplicationJsonMediaType(requestBody.content), E.map((mediaTypeObject) => O.fold(() => blankOutputSchema(), (schema) => appendInPropertyToBody(schema))(mediaTypeObject.schema)));
|
|
113
121
|
}
|
|
114
122
|
if (requestBody && parameters) {
|
|
115
123
|
const params = transformInput(parameters);
|
|
116
|
-
|
|
117
|
-
const bodyWithInProperty = appendInPropertyToBody(body);
|
|
118
|
-
const mergedParamsAndBody = mergeParamsAndBody(params, bodyWithInProperty);
|
|
119
|
-
return mergedParamsAndBody;
|
|
124
|
+
return (0, function_1.pipe)(getApplicationJsonMediaType(requestBody.content), E.map((mediaTypeObject) => O.fold(() => blankOutputSchema(), (schema) => appendInPropertyToBody(schema))(mediaTypeObject.schema)), E.chain((schema) => E.right(mergeParamsAndBody(params, schema))));
|
|
120
125
|
}
|
|
121
|
-
return
|
|
122
|
-
type: O.none,
|
|
123
|
-
properties: O.none,
|
|
124
|
-
required: O.none,
|
|
125
|
-
additionalProperties: O.some(false),
|
|
126
|
-
allOf: O.none,
|
|
127
|
-
anyOf: O.none,
|
|
128
|
-
oneOf: O.none,
|
|
129
|
-
not: O.none,
|
|
130
|
-
in: O.none,
|
|
131
|
-
};
|
|
126
|
+
return E.right(blankOutputSchema());
|
|
132
127
|
};
|
|
133
128
|
exports.generateInputSchema = generateInputSchema;
|
|
@@ -32,6 +32,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
32
32
|
});
|
|
33
33
|
};
|
|
34
34
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
+
const E = __importStar(require("fp-ts/Either"));
|
|
35
36
|
const TE = __importStar(require("fp-ts/TaskEither"));
|
|
36
37
|
const O = __importStar(require("fp-ts/Option"));
|
|
37
38
|
const GenerateInputSchema_1 = require("./GenerateInputSchema");
|
|
@@ -46,12 +47,38 @@ describe('GenerateInputSchema', () => {
|
|
|
46
47
|
{
|
|
47
48
|
name: 'id',
|
|
48
49
|
in: 'path',
|
|
49
|
-
required: true,
|
|
50
|
+
required: O.some(true),
|
|
50
51
|
description: 'The user id.',
|
|
51
52
|
schema: {
|
|
52
|
-
type: 'integer',
|
|
53
|
-
|
|
53
|
+
type: O.some('integer'),
|
|
54
|
+
properties: O.none,
|
|
55
|
+
additionalProperties: O.some(false),
|
|
56
|
+
required: O.none,
|
|
57
|
+
allOf: O.none,
|
|
58
|
+
anyOf: O.none,
|
|
59
|
+
oneOf: O.none,
|
|
60
|
+
not: O.none,
|
|
61
|
+
in: O.none,
|
|
62
|
+
},
|
|
63
|
+
additionalProperties: O.none,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: 'date',
|
|
67
|
+
in: 'query',
|
|
68
|
+
required: O.none,
|
|
69
|
+
description: 'The date of the post.',
|
|
70
|
+
schema: {
|
|
71
|
+
type: O.some('string'),
|
|
72
|
+
properties: O.none,
|
|
73
|
+
additionalProperties: O.some(false),
|
|
74
|
+
format: O.none,
|
|
54
75
|
items: O.none,
|
|
76
|
+
required: O.none,
|
|
77
|
+
allOf: O.none,
|
|
78
|
+
anyOf: O.none,
|
|
79
|
+
oneOf: O.none,
|
|
80
|
+
not: O.none,
|
|
81
|
+
in: O.none,
|
|
55
82
|
},
|
|
56
83
|
additionalProperties: O.none,
|
|
57
84
|
},
|
|
@@ -59,7 +86,9 @@ describe('GenerateInputSchema', () => {
|
|
|
59
86
|
requestBody: O.none,
|
|
60
87
|
responses: O.none,
|
|
61
88
|
};
|
|
62
|
-
const inputSchema =
|
|
89
|
+
const inputSchema = E.getOrElse(() => {
|
|
90
|
+
throw new Error('Should have been right');
|
|
91
|
+
})((0, GenerateInputSchema_1.generateInputSchema)(endpoint));
|
|
63
92
|
const inputTypes = (0, GenerateInputTypes_1.generateInputTypes)(endpoint.operationId, inputSchema);
|
|
64
93
|
const generatedInputFile = yield TE.getOrElse((error) => {
|
|
65
94
|
throw new Error('Should have been right');
|
|
@@ -69,6 +98,10 @@ describe('GenerateInputSchema', () => {
|
|
|
69
98
|
* @description The user id.
|
|
70
99
|
*/
|
|
71
100
|
id: number;
|
|
101
|
+
/**
|
|
102
|
+
* @description The date of the post.
|
|
103
|
+
*/
|
|
104
|
+
date?: string;
|
|
72
105
|
}
|
|
73
106
|
`;
|
|
74
107
|
expect(generatedInputFile).toEqual(expectedInputFile);
|
|
@@ -143,7 +176,9 @@ describe('GenerateInputSchema', () => {
|
|
|
143
176
|
}),
|
|
144
177
|
responses: O.none,
|
|
145
178
|
};
|
|
146
|
-
const inputSchema =
|
|
179
|
+
const inputSchema = E.getOrElse(() => {
|
|
180
|
+
throw new Error('Should have been right');
|
|
181
|
+
})((0, GenerateInputSchema_1.generateInputSchema)(endpoint));
|
|
147
182
|
const inputTypes = (0, GenerateInputTypes_1.generateInputTypes)(endpoint.operationId, inputSchema);
|
|
148
183
|
const generatedInputFile = yield TE.getOrElse((error) => {
|
|
149
184
|
throw new Error('Should have been right');
|
|
@@ -166,12 +201,12 @@ describe('GenerateInputSchema', () => {
|
|
|
166
201
|
{
|
|
167
202
|
name: 'tags',
|
|
168
203
|
in: 'query',
|
|
169
|
-
required: true,
|
|
204
|
+
required: O.some(true),
|
|
170
205
|
description: 'tags to filter by.',
|
|
171
206
|
schema: {
|
|
172
207
|
type: 'array',
|
|
173
208
|
format: O.none,
|
|
174
|
-
items:
|
|
209
|
+
items: {
|
|
175
210
|
type: O.some('string'),
|
|
176
211
|
properties: O.none,
|
|
177
212
|
additionalProperties: O.some(false),
|
|
@@ -181,7 +216,15 @@ describe('GenerateInputSchema', () => {
|
|
|
181
216
|
oneOf: O.none,
|
|
182
217
|
not: O.none,
|
|
183
218
|
in: O.none,
|
|
184
|
-
}
|
|
219
|
+
},
|
|
220
|
+
properties: O.none,
|
|
221
|
+
additionalProperties: O.some(false),
|
|
222
|
+
required: O.none,
|
|
223
|
+
allOf: O.none,
|
|
224
|
+
anyOf: O.none,
|
|
225
|
+
oneOf: O.none,
|
|
226
|
+
not: O.none,
|
|
227
|
+
in: O.none,
|
|
185
228
|
},
|
|
186
229
|
additionalProperties: O.none,
|
|
187
230
|
},
|
|
@@ -189,7 +232,9 @@ describe('GenerateInputSchema', () => {
|
|
|
189
232
|
requestBody: O.none,
|
|
190
233
|
responses: O.none,
|
|
191
234
|
};
|
|
192
|
-
const inputSchema =
|
|
235
|
+
const inputSchema = E.getOrElse(() => {
|
|
236
|
+
throw new Error('Should have been right');
|
|
237
|
+
})((0, GenerateInputSchema_1.generateInputSchema)(endpoint));
|
|
193
238
|
const inputTypes = (0, GenerateInputTypes_1.generateInputTypes)(endpoint.operationId, inputSchema);
|
|
194
239
|
const generatedInputFile = yield TE.getOrElse((error) => {
|
|
195
240
|
throw new Error('Should have been right');
|
|
@@ -32,6 +32,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
32
32
|
});
|
|
33
33
|
};
|
|
34
34
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
+
const E = __importStar(require("fp-ts/Either"));
|
|
35
36
|
const TE = __importStar(require("fp-ts/TaskEither"));
|
|
36
37
|
const O = __importStar(require("fp-ts/Option"));
|
|
37
38
|
const GenerateInputSchema_1 = require("./GenerateInputSchema");
|
|
@@ -107,7 +108,9 @@ describe('GenerateInputType', () => {
|
|
|
107
108
|
}),
|
|
108
109
|
responses: O.none,
|
|
109
110
|
};
|
|
110
|
-
const inputSchema =
|
|
111
|
+
const inputSchema = E.getOrElse(() => {
|
|
112
|
+
throw new Error('Should have been right');
|
|
113
|
+
})((0, GenerateInputSchema_1.generateInputSchema)(endpoint));
|
|
111
114
|
const expectedInputSchema = {
|
|
112
115
|
type: O.some('object'),
|
|
113
116
|
required: O.some(['id', 'userId', 'title', 'body']),
|
|
@@ -175,23 +178,37 @@ describe('GenerateInputType', () => {
|
|
|
175
178
|
{
|
|
176
179
|
name: 'id',
|
|
177
180
|
in: 'path',
|
|
178
|
-
required: true,
|
|
181
|
+
required: O.some(true),
|
|
179
182
|
description: 'The user id.',
|
|
180
183
|
schema: {
|
|
181
|
-
type: 'integer',
|
|
184
|
+
type: O.some('integer'),
|
|
182
185
|
format: O.some('int64'),
|
|
183
|
-
|
|
186
|
+
properties: O.none,
|
|
187
|
+
additionalProperties: O.some(false),
|
|
188
|
+
required: O.none,
|
|
189
|
+
allOf: O.none,
|
|
190
|
+
anyOf: O.none,
|
|
191
|
+
oneOf: O.none,
|
|
192
|
+
not: O.none,
|
|
193
|
+
in: O.none,
|
|
184
194
|
},
|
|
185
195
|
},
|
|
186
196
|
{
|
|
187
197
|
name: 'categoryId',
|
|
188
198
|
in: 'path',
|
|
189
|
-
required: false,
|
|
199
|
+
required: O.some(false),
|
|
190
200
|
description: 'The category id.',
|
|
191
201
|
schema: {
|
|
192
|
-
type: 'integer',
|
|
202
|
+
type: O.some('integer'),
|
|
193
203
|
format: O.some('int64'),
|
|
194
|
-
|
|
204
|
+
properties: O.none,
|
|
205
|
+
additionalProperties: O.some(false),
|
|
206
|
+
required: O.none,
|
|
207
|
+
allOf: O.none,
|
|
208
|
+
anyOf: O.none,
|
|
209
|
+
oneOf: O.none,
|
|
210
|
+
not: O.none,
|
|
211
|
+
in: O.none,
|
|
195
212
|
},
|
|
196
213
|
},
|
|
197
214
|
]),
|
|
@@ -248,7 +265,9 @@ describe('GenerateInputType', () => {
|
|
|
248
265
|
}),
|
|
249
266
|
responses: O.none,
|
|
250
267
|
};
|
|
251
|
-
const inputSchema =
|
|
268
|
+
const inputSchema = E.getOrElse(() => {
|
|
269
|
+
throw new Error('Should have been right');
|
|
270
|
+
})((0, GenerateInputSchema_1.generateInputSchema)(endpoint));
|
|
252
271
|
const inputTypes = (0, GenerateInputTypes_1.generateInputTypes)(endpoint.operationId, inputSchema);
|
|
253
272
|
const generatedInputFile = yield TE.getOrElse((error) => {
|
|
254
273
|
throw new Error('Should have been right');
|
|
@@ -278,7 +297,9 @@ describe('GenerateInputType', () => {
|
|
|
278
297
|
requestBody: O.none,
|
|
279
298
|
responses: O.none,
|
|
280
299
|
};
|
|
281
|
-
const inputSchema =
|
|
300
|
+
const inputSchema = E.getOrElse(() => {
|
|
301
|
+
throw new Error('Should have been right');
|
|
302
|
+
})((0, GenerateInputSchema_1.generateInputSchema)(endpoint));
|
|
282
303
|
const inputTypes = (0, GenerateInputTypes_1.generateInputTypes)(endpoint.operationId, inputSchema);
|
|
283
304
|
const generatedInputFile = yield TE.getOrElse((error) => {
|
|
284
305
|
throw new Error('Should have been right');
|
|
@@ -312,7 +333,9 @@ describe('GenerateInputType', () => {
|
|
|
312
333
|
}),
|
|
313
334
|
responses: O.none,
|
|
314
335
|
};
|
|
315
|
-
const inputSchema =
|
|
336
|
+
const inputSchema = E.getOrElse(() => {
|
|
337
|
+
throw new Error('Should have been right');
|
|
338
|
+
})((0, GenerateInputSchema_1.generateInputSchema)(endpoint));
|
|
316
339
|
const inputTypes = (0, GenerateInputTypes_1.generateInputTypes)(endpoint.operationId, inputSchema);
|
|
317
340
|
const generatedInputFile = yield TE.getOrElse((error) => {
|
|
318
341
|
throw new Error('Should have been right');
|
|
@@ -393,8 +416,10 @@ describe('GenerateInputType', () => {
|
|
|
393
416
|
}),
|
|
394
417
|
responses: O.none,
|
|
395
418
|
};
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
419
|
+
const inputSchema = (0, GenerateInputSchema_1.generateInputSchema)(endpoint);
|
|
420
|
+
if (E.isRight(inputSchema)) {
|
|
421
|
+
throw new Error('Should have been left');
|
|
422
|
+
}
|
|
423
|
+
expect(inputSchema.left.message).toEqual('Unsupported media type: unsupported-media-type');
|
|
399
424
|
}));
|
|
400
425
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GenerateOutput.d.ts","sourceRoot":"","sources":["../../../src/file-generators/types/GenerateOutput.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAClC,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAKlC,OAAO,EACN,SAAS,EAET,eAAe,EACf,YAAY,EAEZ,MAAM,8BAA8B,CAAC;AAuCtC,eAAO,MAAM,2BAA2B,YAC9B,OAAO,MAAM,EAAE,eAAe,CAAC,KACtC,EAAE,MAAM,CAAC,KAAK,EAAE,eAAe,CAWjC,CAAC;AAEF,eAAO,MAAM,oBAAoB,cACrB,EAAE,MAAM,CAAC,SAAS,CAAC,KAC5B,GAAG,UAAU,CAAC,KAAK,EAAE,YAAY,CAelC,CAAC;AAWH,eAAO,MAAM,mBAAmB,2BACP,MAAM,gBAChB,YAAY,KACxB,GAAG,UAAU,CAAC,KAAK,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"GenerateOutput.d.ts","sourceRoot":"","sources":["../../../src/file-generators/types/GenerateOutput.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAClC,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAKlC,OAAO,EACN,SAAS,EAET,eAAe,EACf,YAAY,EAEZ,MAAM,8BAA8B,CAAC;AAuCtC,eAAO,MAAM,2BAA2B,YAC9B,OAAO,MAAM,EAAE,eAAe,CAAC,KACtC,EAAE,MAAM,CAAC,KAAK,EAAE,eAAe,CAWjC,CAAC;AAEF,eAAO,MAAM,oBAAoB,cACrB,EAAE,MAAM,CAAC,SAAS,CAAC,KAC5B,GAAG,UAAU,CAAC,KAAK,EAAE,YAAY,CAelC,CAAC;AAWH,eAAO,MAAM,mBAAmB,2BACP,MAAM,gBAChB,YAAY,KACxB,GAAG,UAAU,CAAC,KAAK,EAAE,MAAM,CAY7B,CAAC"}
|
|
@@ -72,9 +72,6 @@ const encodeOutputSchema = (outputSchema) => {
|
|
|
72
72
|
};
|
|
73
73
|
const generateOutputTypes = (operationNameCamelCase, outputSchema) => {
|
|
74
74
|
const resolvedOutputSchema = encodeOutputSchema(outputSchema);
|
|
75
|
-
return TE.tryCatch(() => (0, json_schema_to_typescript_1.compile)(resolvedOutputSchema, `${operationNameCamelCase}Output`, JsonSchemaToTypescriptOptions_1.JsonSchemaToTypescriptOptions), (error) => {
|
|
76
|
-
console.log(JSON.stringify(resolvedOutputSchema));
|
|
77
|
-
return new Error(`Failed to generate output types: ${error}`);
|
|
78
|
-
});
|
|
75
|
+
return TE.tryCatch(() => (0, json_schema_to_typescript_1.compile)(resolvedOutputSchema, `${operationNameCamelCase}Output`, JsonSchemaToTypescriptOptions_1.JsonSchemaToTypescriptOptions), (error) => new Error(`Failed to generate output types: ${error}`));
|
|
79
76
|
};
|
|
80
77
|
exports.generateOutputTypes = generateOutputTypes;
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
{
|
|
2
|
+
"openapi": "3.0.0",
|
|
3
|
+
"info": {
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"title": "JSON Placeholder API",
|
|
6
|
+
"description": "See https://jsonplaceholder.typicode.com/"
|
|
7
|
+
},
|
|
8
|
+
"servers": [
|
|
9
|
+
{
|
|
10
|
+
"url": "https://jsonplaceholder.typicode.com"
|
|
11
|
+
}
|
|
12
|
+
],
|
|
13
|
+
"paths": {
|
|
14
|
+
"/posts/{id}/{uuid}": {
|
|
15
|
+
"parameters": [
|
|
16
|
+
{
|
|
17
|
+
"name": "id",
|
|
18
|
+
"in": "path",
|
|
19
|
+
"required": true,
|
|
20
|
+
"description": "The user id.",
|
|
21
|
+
"schema": {
|
|
22
|
+
"type": "integer",
|
|
23
|
+
"format": "int64"
|
|
24
|
+
},
|
|
25
|
+
"additionalProperties": false
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"in": "path",
|
|
29
|
+
"name": "uuid",
|
|
30
|
+
"description": "UUID.",
|
|
31
|
+
"required": true,
|
|
32
|
+
"schema": {
|
|
33
|
+
"allOf": [
|
|
34
|
+
{
|
|
35
|
+
"title": "UUID Property",
|
|
36
|
+
"description": "A string that has to be a format matching the industry standard uuid",
|
|
37
|
+
"type": "string",
|
|
38
|
+
"format": "uuid",
|
|
39
|
+
"example": "04ca6ae2-0dc3-487b-953e-86d6abbdf7d3"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"example": "b054dd32-efb6-444a-b4a6-a797a18315ef"
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
],
|
|
48
|
+
"put": {
|
|
49
|
+
"tags": ["post"],
|
|
50
|
+
"requestBody": {
|
|
51
|
+
"content": {
|
|
52
|
+
"application/json": {
|
|
53
|
+
"schema": {
|
|
54
|
+
"type": "object",
|
|
55
|
+
"required": ["id", "userId", "title", "body"],
|
|
56
|
+
"properties": {
|
|
57
|
+
"id": {
|
|
58
|
+
"type": "integer"
|
|
59
|
+
},
|
|
60
|
+
"userId": {
|
|
61
|
+
"type": "integer"
|
|
62
|
+
},
|
|
63
|
+
"title": {
|
|
64
|
+
"type": "string"
|
|
65
|
+
},
|
|
66
|
+
"body": {
|
|
67
|
+
"type": "string"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"required": true
|
|
74
|
+
},
|
|
75
|
+
"responses": {
|
|
76
|
+
"200": {
|
|
77
|
+
"description": "All went well",
|
|
78
|
+
"content": {
|
|
79
|
+
"application/json": {
|
|
80
|
+
"schema": {
|
|
81
|
+
"$ref": "#/components/schemas/Post"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"404": {
|
|
87
|
+
"description": "Post not found",
|
|
88
|
+
"content": {
|
|
89
|
+
"application/json": {
|
|
90
|
+
"schema": {
|
|
91
|
+
"type": "object",
|
|
92
|
+
"properties": {}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"get": {
|
|
100
|
+
"description": "Returns a post by id",
|
|
101
|
+
"tags": ["Posts"],
|
|
102
|
+
"operationId": "getPost",
|
|
103
|
+
"parameters": [
|
|
104
|
+
{
|
|
105
|
+
"name": "date",
|
|
106
|
+
"in": "query",
|
|
107
|
+
"description": "The post date.",
|
|
108
|
+
"schema": {
|
|
109
|
+
"type": "string"
|
|
110
|
+
},
|
|
111
|
+
"additionalProperties": false
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
"responses": {
|
|
115
|
+
"200": {
|
|
116
|
+
"description": "Successful response",
|
|
117
|
+
"content": {
|
|
118
|
+
"application/json": {
|
|
119
|
+
"schema": {
|
|
120
|
+
"$ref": "#/components/schemas/PostsList"
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
"404": {
|
|
126
|
+
"description": "Post not found"
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
"components": {
|
|
133
|
+
"schemas": {
|
|
134
|
+
"PostsList": {
|
|
135
|
+
"type": "array",
|
|
136
|
+
"items": {
|
|
137
|
+
"$ref": "#/components/schemas/Post"
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
"Post": {
|
|
141
|
+
"type": "object",
|
|
142
|
+
"required": ["id", "userId", "title", "body"],
|
|
143
|
+
"properties": {
|
|
144
|
+
"id": {
|
|
145
|
+
"type": "integer"
|
|
146
|
+
},
|
|
147
|
+
"userId": {
|
|
148
|
+
"type": "integer"
|
|
149
|
+
},
|
|
150
|
+
"title": {
|
|
151
|
+
"type": "string"
|
|
152
|
+
},
|
|
153
|
+
"body": {
|
|
154
|
+
"type": "string"
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
package/package.json
CHANGED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"openapi": "3.0.0",
|
|
3
|
-
"info": {
|
|
4
|
-
"version": "1.0.0",
|
|
5
|
-
"title": "JSON Placeholder API",
|
|
6
|
-
"description": "See https://jsonplaceholder.typicode.com/"
|
|
7
|
-
},
|
|
8
|
-
"servers": [
|
|
9
|
-
{
|
|
10
|
-
"url": "https://jsonplaceholder.typicode.com"
|
|
11
|
-
}
|
|
12
|
-
],
|
|
13
|
-
"paths": {
|
|
14
|
-
"/posts/{id}": {
|
|
15
|
-
"get": {
|
|
16
|
-
"description": "Returns a post by id",
|
|
17
|
-
"tags": ["Posts"],
|
|
18
|
-
"operationId": "getPost",
|
|
19
|
-
"parameters": [
|
|
20
|
-
{
|
|
21
|
-
"name": "id",
|
|
22
|
-
"in": "path",
|
|
23
|
-
"required": true,
|
|
24
|
-
"description": "The user id.",
|
|
25
|
-
"schema": {
|
|
26
|
-
"type": "integer",
|
|
27
|
-
"format": "int64"
|
|
28
|
-
},
|
|
29
|
-
"additionalProperties": false
|
|
30
|
-
}
|
|
31
|
-
],
|
|
32
|
-
"responses": {
|
|
33
|
-
"200": {
|
|
34
|
-
"description": "Successful response",
|
|
35
|
-
"content": {
|
|
36
|
-
"application/json": {
|
|
37
|
-
"schema": {
|
|
38
|
-
"$ref": "#/components/schemas/PostsList"
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
"404": {
|
|
44
|
-
"description": "Post not found"
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
},
|
|
50
|
-
"components": {
|
|
51
|
-
"schemas": {
|
|
52
|
-
"PostsList": {
|
|
53
|
-
"type": "array",
|
|
54
|
-
"items": {
|
|
55
|
-
"$ref": "#/components/schemas/Post"
|
|
56
|
-
}
|
|
57
|
-
},
|
|
58
|
-
"Post": {
|
|
59
|
-
"type": "object",
|
|
60
|
-
"required": ["id", "userId", "title", "body"],
|
|
61
|
-
"properties": {
|
|
62
|
-
"id": {
|
|
63
|
-
"type": "integer"
|
|
64
|
-
},
|
|
65
|
-
"userId": {
|
|
66
|
-
"type": "integer"
|
|
67
|
-
},
|
|
68
|
-
"title": {
|
|
69
|
-
"type": "string"
|
|
70
|
-
},
|
|
71
|
-
"body": {
|
|
72
|
-
"type": "string"
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|