UNPKG

6.19 kBJavaScriptView Raw
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3 return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6const path_1 = __importDefault(require("path"));
7const typescript_1 = __importDefault(require("typescript"));
8const openapi_template_1 = require("./openapi-template");
9const convert_type_1 = require("./convert-type");
10exports.FUNCTION_ACTION = 'action';
11/**
12 * find action method in class and return relevant node
13 */
14function 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}
26function 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; // index of ReturnedData in TFetchPromise<ReturnedData, ReturnedError>
33 const errorIndex = 1; // index of ReturnedError in TFetchPromise<ReturnedData, ReturnedError>
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 * Find the Parameter type in func and convert it to json-schema
48 */
49function 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 * Find the auth context type and return it's name
59 * @param sym action method symbol
60 * @param node action method symbol value declaration
61 * @param checker program type checker
62 */
63function 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 * Convert single func types to json schema
86 * This function tries to find the relevant type definitions, Params and `action` method resposne type
87 * and converts the types to json-schema
88 * @param functionPath absolute path to function
89 * @param options compiler options
90 */
91function 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 // Only consider exported nodes
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}
124exports.functionTypesToSchemaConverter = functionTypesToSchemaConverter;
125/**
126 * Generate full openapi spec from functions
127 * @param functionsDir absolute path to functions directory
128 * @param functions list of func names
129 * @param integrationUuid integration unique identifier
130 * @param integrationName name of the integration
131 */
132function 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}
147exports.default = generator;