UNPKG

6.02 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 (/Basic/.test(authType))
71 return 'BASIC';
72 if (/OAuth1/.test(authType))
73 return 'OAUTH1';
74 if (/OAuth2/.test(authType))
75 return 'OAUTH2';
76 if (/None/.test(authType))
77 return 'NONE';
78 return authType;
79 }
80 }
81 return;
82}
83/**
84 * Convert single func types to json schema
85 * This function tries to find the relevant type definitions, Params and `action` method resposne type
86 * and converts the types to json-schema
87 * @param functionPath absolute path to function
88 * @param options compiler options
89 */
90function functionTypesToSchemaConverter(functionPath, options = { target: typescript_1.default.ScriptTarget.ES5, module: typescript_1.default.ModuleKind.CommonJS }) {
91 const program = typescript_1.default.createProgram([functionPath], options);
92 const sourceFile = program.getSourceFile(functionPath);
93 const checker = program.getTypeChecker();
94 const output = {
95 requestBody: {},
96 response: {}
97 };
98 if (sourceFile) {
99 typescript_1.default.forEachChild(sourceFile, visit);
100 }
101 return output;
102 function visit(node) {
103 // Only consider exported nodes
104 if (!isNodeExported(node)) {
105 return;
106 }
107 if (typescript_1.default.isClassDeclaration(node) && node.name) {
108 const actionMethodNode = findActionMethod(node);
109 if (actionMethodNode) {
110 const parameterNode = actionMethodNode.parameters[0];
111 const sym = checker.getSymbolAtLocation(parameterNode.name);
112 output.requestBody = serializeParameters(sym, parameterNode, checker);
113 output.response = serializeBody(actionMethodNode, checker);
114 output.functionAuthType = getFunctionAuthType(sym, parameterNode, checker);
115 }
116 }
117 }
118 function isNodeExported(node) {
119 return ((typescript_1.default.getCombinedModifierFlags(node) & typescript_1.default.ModifierFlags.Export) !== 0 ||
120 (!!node.parent && node.parent.kind === typescript_1.default.SyntaxKind.SourceFile));
121 }
122}
123exports.functionTypesToSchemaConverter = functionTypesToSchemaConverter;
124/**
125 * Generate full openapi spec from functions
126 * @param functionsDir absolute path to functions directory
127 * @param functions list of func names
128 * @param buid integration unique identifier
129 * @param integrationName name of the integration
130 */
131function generator({ functionsDir, functions, buid, integrationName }) {
132 const doc = openapi_template_1.topOfSpec(integrationName);
133 const schemas = functions.sort().reduce((acc, func) => {
134 const functionPath = path_1.default.join(functionsDir, `${func}.ts`);
135 const typeSchema = functionTypesToSchemaConverter(functionPath);
136 return Object.assign(acc, openapi_template_1.specPath({
137 buid,
138 functionName: func,
139 response: { type: 'object', properties: typeSchema.response },
140 requestBody: typeSchema.requestBody,
141 oauth: typeSchema.functionAuthType === 'OAUTH2' || typeSchema.functionAuthType === 'OAUTH1'
142 }));
143 }, {});
144 return JSON.stringify(Object.assign(doc, { paths: schemas }), null, 2);
145}
146exports.default = generator;