1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const functions = require("@bearer/functions");
|
4 | const fs = require("fs");
|
5 | const globby = require("globby");
|
6 | const path = require("path");
|
7 | const ts = require("typescript");
|
8 | const TJS = require("typescript-json-schema");
|
9 | const openapi_generator_1 = require("@bearer/openapi-generator");
|
10 | const config = ts.readConfigFile(path.join(__dirname, '../../templates/start', 'tsconfig.json'), ts.sys.readFile);
|
11 | const NON_FUNCTION_NAMES = ['DBClient'];
|
12 | const FUNCTION_NAMES = Object.keys(functions).filter(functionName => !NON_FUNCTION_NAMES.includes(functionName));
|
13 | const FUNCTION_TYPE_IDENTIFIER = 'functionType';
|
14 | const functionEntries = [];
|
15 | function bodySchema(tsType, generator) {
|
16 | return {};
|
17 | }
|
18 | class FunctionNodeAdapter {
|
19 | constructor(functionName, node,
|
20 | // @ts-ignore
|
21 | generator) {
|
22 | this.functionName = functionName;
|
23 | this.node = node;
|
24 | this.generator = generator;
|
25 | }
|
26 | get functionClassName() {
|
27 | return getIdentifier(this.node).escapedText.toString();
|
28 | }
|
29 | get functionType() {
|
30 | return getPropertyValue(this.node, FUNCTION_TYPE_IDENTIFIER);
|
31 | }
|
32 | get paramsSchema() {
|
33 | return [...DEFAULT_PARAMS];
|
34 | }
|
35 | adaptParamsSchema({ properties = {} }) {
|
36 | if (properties) {
|
37 | return Object.keys(properties).map(propName => {
|
38 | const { schema, required, name, description } = properties[propName];
|
39 | return {
|
40 | schema: schema || { type: 'string' },
|
41 | in: 'query',
|
42 | description: description || propName,
|
43 | required: required !== undefined ? required : true,
|
44 | name: name || propName
|
45 | };
|
46 | });
|
47 | }
|
48 | return [];
|
49 | }
|
50 | get bodySchema() {
|
51 | return {
|
52 | properties: bodySchema(this.node, this.generator)
|
53 | };
|
54 | }
|
55 | get outputSchema() {
|
56 | return {};
|
57 | }
|
58 | get adapt() {
|
59 | return {
|
60 | functionClassName: this.functionClassName,
|
61 | functionName: this.functionName,
|
62 | functionType: this.functionType,
|
63 | paramsSchema: this.paramsSchema,
|
64 | bodySchema: this.bodySchema,
|
65 | outputSchema: this.outputSchema
|
66 | };
|
67 | }
|
68 | }
|
69 | function isFunctionClass(tsNode) {
|
70 | if (!ts.isClassDeclaration(tsNode)) {
|
71 | return false;
|
72 | }
|
73 | return extendsFunctionType(tsNode) && implementsAction(tsNode);
|
74 | }
|
75 | exports.isFunctionClass = isFunctionClass;
|
76 | function extendsFunctionType(tsClass) {
|
77 | const extendedClasses = (tsClass.heritageClauses || []).filter(hc => hc.token === ts.SyntaxKind.ExtendsKeyword);
|
78 | return Boolean(extendedClasses.find(hc => Boolean(hc.types.find(t => FUNCTION_NAMES.includes(t.expression.escapedText.toString())))));
|
79 | }
|
80 | function implementsAction(tsClass) {
|
81 | return Boolean(tsClass.members.filter(m => {
|
82 | return ts.isMethodDeclaration(m);
|
83 | }));
|
84 | }
|
85 | function getIdentifier(tsNode) {
|
86 | return tsNode.name;
|
87 | }
|
88 | exports.getIdentifier = getIdentifier;
|
89 | function getFunctionName(tsSourceFile) {
|
90 | return path.basename(tsSourceFile.fileName).split('.')[0];
|
91 | }
|
92 | exports.getFunctionName = getFunctionName;
|
93 | function getPropertyValue(tsNode, propertyName) {
|
94 | if (tsNode.members) {
|
95 | const declaration = tsNode.members.find(node => {
|
96 | return ts.isPropertyDeclaration(node) && node.name.escapedText.toString() === propertyName;
|
97 | });
|
98 | if (declaration && declaration.initializer) {
|
99 | return declaration.initializer.text;
|
100 | }
|
101 | }
|
102 | }
|
103 | exports.getPropertyValue = getPropertyValue;
|
104 | function transformer(generator) {
|
105 | return (context) => {
|
106 | return (tsSourceFile) => {
|
107 | function visit(tsNode) {
|
108 | if (isFunctionClass(tsNode)) {
|
109 | const adapter = new FunctionNodeAdapter(getFunctionName(tsSourceFile), tsNode, generator);
|
110 | functionEntries.push(adapter.adapt);
|
111 | }
|
112 | return tsNode;
|
113 | }
|
114 | return ts.visitEachChild(tsSourceFile, visit, context);
|
115 | };
|
116 | };
|
117 | }
|
118 | exports.transformer = transformer;
|
119 | class FunctionCodeProcessor {
|
120 | constructor(srcFunctionsDir, transformer) {
|
121 | this.srcFunctionsDir = srcFunctionsDir;
|
122 | this.transformer = transformer;
|
123 | }
|
124 | async run() {
|
125 | const files = await globby(`${this.srcFunctionsDir}/*.ts`);
|
126 | files.forEach(file => {
|
127 | const sourceFile = ts.createSourceFile(file, fs.readFileSync(file, 'utf8'), ts.ScriptTarget.Latest, false, ts.ScriptKind.TSX);
|
128 | ts.transform(sourceFile, [this.transformer]);
|
129 | });
|
130 | }
|
131 | }
|
132 | exports.FunctionCodeProcessor = FunctionCodeProcessor;
|
133 | class OpenApiSpecGenerator {
|
134 | constructor(srcFunctionsDir, bearerConfig) {
|
135 | this.srcFunctionsDir = srcFunctionsDir;
|
136 | this.bearerConfig = bearerConfig;
|
137 | }
|
138 | async build() {
|
139 | const files = await globby(`${this.srcFunctionsDir}/*.ts`);
|
140 | const programGenerator = TJS.getProgramFromFiles(files, Object.assign({}, config.config.compilerOptions, { allowUnusedLabels: true,
|
141 |
|
142 | noUnusedParameters: false, noUnusedLocals: false }), './ok');
|
143 | const generator = TJS.buildGenerator(programGenerator, {
|
144 | required: true
|
145 | });
|
146 | if (!generator) {
|
147 | throw new Error('Please fix above issues before');
|
148 | }
|
149 | files.forEach(file => {
|
150 | const sourceFile = ts.createSourceFile(file, fs.readFileSync(file, 'utf8'), ts.ScriptTarget.Latest, false, ts.ScriptKind.TSX);
|
151 | ts.transform(sourceFile, [transformer(generator)]);
|
152 | });
|
153 | return openapi_generator_1.default({
|
154 | functions: functionEntries.map(entry => entry.functionName),
|
155 | functionsDir: this.srcFunctionsDir,
|
156 | integrationUuid: this.bearerConfig.integrationUuid,
|
157 | integrationName: this.bearerConfig.integrationTitle || ''
|
158 | });
|
159 | }
|
160 | }
|
161 | exports.OpenApiSpecGenerator = OpenApiSpecGenerator;
|
162 | const DEFAULT_PARAMS = [
|
163 | {
|
164 | in: 'header',
|
165 | name: 'authorization',
|
166 | schema: {
|
167 | type: 'string'
|
168 | },
|
169 | description: 'API Key',
|
170 | required: true
|
171 | }
|
172 |
|
173 |
|
174 |
|
175 |
|
176 |
|
177 |
|
178 |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 | ];
|