1 | "use strict";
|
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
4 | };
|
5 | Object.defineProperty(exports, "__esModule", { value: true });
|
6 | const path_1 = __importDefault(require("path"));
|
7 | const typescript_1 = __importDefault(require("typescript"));
|
8 | const openapi_template_1 = require("./openapi-template");
|
9 | const convert_type_1 = require("./convert-type");
|
10 | exports.FUNCTION_ACTION = 'action';
|
11 |
|
12 |
|
13 |
|
14 | function findActionMethod(node) {
|
15 | const action = node.members.find((node) => {
|
16 | if (node.name) {
|
17 | return node.name.getText() === exports.FUNCTION_ACTION;
|
18 | }
|
19 | return false;
|
20 | });
|
21 | if (typescript_1.default.isPropertyDeclaration(action)) {
|
22 | return action.initializer;
|
23 | }
|
24 | return action;
|
25 | }
|
26 | function serializeBody(method, checker) {
|
27 | const symbol = checker.getSymbolAtLocation(method.name);
|
28 | let data;
|
29 | let error;
|
30 | if (symbol) {
|
31 | const returnTypeNode = method.type;
|
32 | const dataIndex = 0;
|
33 | const errorIndex = 1;
|
34 | if (returnTypeNode && typescript_1.default.isTypeReferenceNode(returnTypeNode)) {
|
35 | const typeData = checker.getTypeFromTypeNode(returnTypeNode.typeArguments[dataIndex]);
|
36 | data = convert_type_1.convertType(typeData, checker);
|
37 | const errorArgument = returnTypeNode.typeArguments[errorIndex];
|
38 | if (errorArgument) {
|
39 | const typeError = checker.getTypeFromTypeNode(errorArgument);
|
40 | error = convert_type_1.convertType(typeError, checker);
|
41 | }
|
42 | }
|
43 | }
|
44 | return { data, error };
|
45 | }
|
46 |
|
47 |
|
48 |
|
49 | function serializeParameters(sym, node, checker) {
|
50 | if (sym) {
|
51 | const typ = checker.getTypeOfSymbolAtLocation(sym, node);
|
52 | if (typ.aliasTypeArguments) {
|
53 | return convert_type_1.convertType(typ.aliasTypeArguments[0], checker);
|
54 | }
|
55 | }
|
56 | }
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 | function getFunctionAuthType(sym, node, checker) {
|
64 | if (sym) {
|
65 | const typ = checker.getTypeOfSymbolAtLocation(sym, node);
|
66 | if (typ.aliasTypeArguments) {
|
67 | const authType = checker.typeToString(typ.aliasTypeArguments[1]);
|
68 | if (/apiKey/.test(authType))
|
69 | return 'APIKEY';
|
70 | if (/username/.test(authType) && /password/.test(authType))
|
71 | return 'BASIC';
|
72 | if ((/accessToken/.test(authType) && /tokenSecret/.test(authType)) || /TOAUTH1AuthContext/.test(authType)) {
|
73 | return 'OAUTH1';
|
74 | }
|
75 | if (/accessToken/.test(authType))
|
76 | return 'OAUTH2';
|
77 | if (/undefined/.test(authType))
|
78 | return 'NONE';
|
79 | return authType;
|
80 | }
|
81 | }
|
82 | return;
|
83 | }
|
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 |
|
91 | function functionTypesToSchemaConverter(functionPath, options = { target: typescript_1.default.ScriptTarget.ES5, module: typescript_1.default.ModuleKind.CommonJS }) {
|
92 | const program = typescript_1.default.createProgram([functionPath], options);
|
93 | const sourceFile = program.getSourceFile(functionPath);
|
94 | const checker = program.getTypeChecker();
|
95 | const output = {
|
96 | requestBody: {},
|
97 | response: {}
|
98 | };
|
99 | if (sourceFile) {
|
100 | typescript_1.default.forEachChild(sourceFile, visit);
|
101 | }
|
102 | return output;
|
103 | function visit(node) {
|
104 |
|
105 | if (!isNodeExported(node)) {
|
106 | return;
|
107 | }
|
108 | if (typescript_1.default.isClassDeclaration(node) && node.name) {
|
109 | const actionMethodNode = findActionMethod(node);
|
110 | if (actionMethodNode) {
|
111 | const parameterNode = actionMethodNode.parameters[0];
|
112 | const sym = checker.getSymbolAtLocation(parameterNode.name);
|
113 | output.requestBody = serializeParameters(sym, parameterNode, checker);
|
114 | output.response = serializeBody(actionMethodNode, checker);
|
115 | output.functionAuthType = getFunctionAuthType(sym, parameterNode, checker);
|
116 | }
|
117 | }
|
118 | }
|
119 | function isNodeExported(node) {
|
120 | return ((typescript_1.default.getCombinedModifierFlags(node) & typescript_1.default.ModifierFlags.Export) !== 0 ||
|
121 | (!!node.parent && node.parent.kind === typescript_1.default.SyntaxKind.SourceFile));
|
122 | }
|
123 | }
|
124 | exports.functionTypesToSchemaConverter = functionTypesToSchemaConverter;
|
125 |
|
126 |
|
127 |
|
128 |
|
129 |
|
130 |
|
131 |
|
132 | function generator({ functionsDir, functions, integrationUuid, integrationName }) {
|
133 | const doc = openapi_template_1.topOfSpec(integrationName);
|
134 | const schemas = functions.sort().reduce((acc, func) => {
|
135 | const functionPath = path_1.default.join(functionsDir, `${func}.ts`);
|
136 | const typeSchema = functionTypesToSchemaConverter(functionPath);
|
137 | return Object.assign(acc, openapi_template_1.specPath({
|
138 | integrationUuid,
|
139 | functionName: func,
|
140 | response: { type: 'object', properties: typeSchema.response },
|
141 | requestBody: typeSchema.requestBody,
|
142 | oauth: typeSchema.functionAuthType === 'OAUTH2' || typeSchema.functionAuthType === 'OAUTH1'
|
143 | }));
|
144 | }, {});
|
145 | return JSON.stringify(Object.assign(doc, { paths: schemas }), null, 2);
|
146 | }
|
147 | exports.default = generator;
|