genezio
Version:
Command line utility to interact with Genezio infrastructure.
186 lines (185 loc) • 9.85 kB
JavaScript
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _GoBundler_instances, _GoBundler_getImportViewFromPath, _GoBundler_mapTypeToGoType, _GoBundler_getCastExpression, _GoBundler_createRouterFileForClass;
import path from "path";
import Mustache from "mustache";
import { default as fsExtra } from "fs-extra";
// Utils
import { createTemporaryFolder, writeToFile } from "../../utils/file.js";
import { debugLogger } from "../../utils/logging.js";
import { AstNodeType, } from "../../models/genezioModels.js";
import { checkIfGoIsInstalled } from "../../utils/go.js";
import { TriggerType } from "../../projectConfiguration/yaml/models.js";
import { UserError } from "../../errors.js";
export class GoBundler {
constructor() {
_GoBundler_instances.add(this);
}
async bundle(input) {
// Create a temporary folder were we copy user code to prepare everything.
const folderPath = input.projectConfiguration.workspace?.backend ?? input.genezioConfigurationFilePath;
const inputTemporaryFolder = await createTemporaryFolder();
await fsExtra.copy(folderPath, inputTemporaryFolder);
debugLogger.info(`Copy files in temp folder ${inputTemporaryFolder}`);
// Create the router class
const userClass = input.projectConfiguration.classes.find((c) => c.path == input.path);
await __classPrivateFieldGet(this, _GoBundler_instances, "m", _GoBundler_createRouterFileForClass).call(this, userClass, input.ast, inputTemporaryFolder);
checkIfGoIsInstalled();
// Compile the Go code on the server
debugLogger.info("Compiling Go...");
input.path = inputTemporaryFolder;
await this.compile(inputTemporaryFolder, input);
debugLogger.info("Compiling Go finished.");
return {
...input,
path: inputTemporaryFolder,
extra: {
...input.extra,
entryFile: "bootstrap",
},
};
}
}
_GoBundler_instances = new WeakSet(), _GoBundler_getImportViewFromPath = function _GoBundler_getImportViewFromPath(path) {
if (!path)
return { name: "", path: "", named: false };
const packageName = path.substring(path.lastIndexOf("/") + 1);
const pathWithoutName = path.substring(0, path.lastIndexOf("/"));
const packagePath = pathWithoutName.substring(pathWithoutName.lastIndexOf("/") + 1);
if (packageName === packagePath)
return { name: packageName, path: pathWithoutName, named: false };
return { name: packageName, path: pathWithoutName, named: true };
}, _GoBundler_mapTypeToGoType = function _GoBundler_mapTypeToGoType(type, ast, imports) {
switch (type.type) {
case AstNodeType.StringLiteral:
return "string";
case AstNodeType.DoubleLiteral:
return "float64";
case AstNodeType.BooleanLiteral:
return "bool";
case AstNodeType.IntegerLiteral:
return "int";
case AstNodeType.CustomNodeLiteral:
for (const node of ast.body ?? []) {
if (node.type === AstNodeType.StructLiteral) {
const struct = node;
if (struct.name === type.rawValue) {
const importView = __classPrivateFieldGet(this, _GoBundler_instances, "m", _GoBundler_getImportViewFromPath).call(this, struct.path ?? "");
// check if import is already present
if (!imports.find((i) => i.path === importView.path)) {
imports.push(importView);
}
return importView.name + "." + struct.name;
}
}
}
return type.rawValue;
case AstNodeType.ArrayType:
return "[]" + __classPrivateFieldGet(this, _GoBundler_instances, "m", _GoBundler_mapTypeToGoType).call(this, type.generic, ast, imports);
case AstNodeType.MapType:
return `map[${__classPrivateFieldGet(this, _GoBundler_instances, "m", _GoBundler_mapTypeToGoType).call(this, type.genericKey, ast, imports)}]${__classPrivateFieldGet(this, _GoBundler_instances, "m", _GoBundler_mapTypeToGoType).call(this, type.genericValue, ast, imports)}`;
case AstNodeType.AnyLiteral:
return "interface{}";
}
return "interface{}";
}, _GoBundler_getCastExpression = function _GoBundler_getCastExpression(index, parameter, ast, imports) {
switch (parameter.type.type) {
case AstNodeType.StringLiteral:
case AstNodeType.DoubleLiteral:
case AstNodeType.BooleanLiteral:
if (parameter.optional) {
return `var param${index} *${__classPrivateFieldGet(this, _GoBundler_instances, "m", _GoBundler_mapTypeToGoType).call(this, parameter.type, ast, imports)}
if body.Params[${index}] == nil {
param${index} = nil
} else {
paramValue${index} := body.Params[${index}].(${__classPrivateFieldGet(this, _GoBundler_instances, "m", _GoBundler_mapTypeToGoType).call(this, parameter.type, ast, imports)})
param${index} = ¶mValue${index}
}`;
}
return `param${index} := body.Params[${index}].(${__classPrivateFieldGet(this, _GoBundler_instances, "m", _GoBundler_mapTypeToGoType).call(this, parameter.type, ast, imports)})`;
case AstNodeType.IntegerLiteral:
if (parameter.optional) {
return `var param${index} *${__classPrivateFieldGet(this, _GoBundler_instances, "m", _GoBundler_mapTypeToGoType).call(this, parameter.type, ast, imports)}
if body.Params[${index}] == nil {
param${index} = nil
} else {
paramValue${index} := body.Params[${index}].(float64)
paramValueInt${index} := int(paramValue${index})
param${index} = ¶mValueInt${index}
}`;
}
return `paramFloat${index} := body.Params[${index}].(float64)
param${index} := int(paramFloat${index})`;
case AstNodeType.CustomNodeLiteral:
if (parameter.type.rawValue === "GnzContext") {
return `param${index} := ctx`;
}
// intentional fallthrough
// eslint-disable-next-line no-fallthrough
case AstNodeType.MapType:
case AstNodeType.ArrayType:
return `var param${index} ${parameter.optional ? "*" : ""}${__classPrivateFieldGet(this, _GoBundler_instances, "m", _GoBundler_mapTypeToGoType).call(this, parameter.type, ast, imports)}
jsonMap, err := json.Marshal(body.Params[${index}])
if err != nil {
${this.generateErrorReturn()}
}
err = json.Unmarshal(jsonMap, ¶m${index})
if err != nil {
${this.generateErrorReturn()}
}`;
case AstNodeType.AnyLiteral:
return `param${index} := body.Params[${index}]`;
}
return "";
}, _GoBundler_createRouterFileForClass = async function _GoBundler_createRouterFileForClass(classConfiguration, ast, folderPath) {
const mainClass = ast.body?.find((element) => {
return (element.type === AstNodeType.ClassDefinition &&
element.name === classConfiguration.name);
});
const classConfigPath = path.dirname(classConfiguration.path);
// Error check: User is using Windows but paths are unix style (possible when cloning projects from git)
if (process.platform === "win32" && classConfigPath.includes("/")) {
throw new UserError("Error: You are using Windows but your project contains unix style paths. Please use Windows style paths in genezio.yaml instead.");
}
const imports = [];
const moustacheViewForMain = {
imports: [],
usesAuth: classConfiguration.methods.some((m) => m.auth),
class: {
name: mainClass.name,
packageName: mainClass.path?.substring(mainClass.path.lastIndexOf("/") + 1),
},
cronMethods: classConfiguration.methods
.filter((m) => m.type === TriggerType.cron)
.map((m) => ({
name: m.name,
})),
httpMethods: classConfiguration.methods
.filter((m) => m.type === TriggerType.http)
.map((m) => ({
name: m.name,
})),
jsonRpcMethods: classConfiguration.methods
.filter((m) => m.type === TriggerType.jsonrpc)
.map((m) => ({
name: m.name,
auth: m.auth ?? false,
isVoid: m.returnType.type === AstNodeType.VoidLiteral,
parameters: m.parameters.map((p, index) => ({
index,
last: index === m.parameters.length - 1,
cast: __classPrivateFieldGet(this, _GoBundler_instances, "m", _GoBundler_getCastExpression).call(this, index, p, ast, imports),
})),
})),
};
moustacheViewForMain.imports.push(...imports);
const classImport = __classPrivateFieldGet(this, _GoBundler_instances, "m", _GoBundler_getImportViewFromPath).call(this, mainClass.path ?? "");
if (!moustacheViewForMain.imports.find((i) => i.path === classImport.path)) {
moustacheViewForMain.imports.push(classImport);
}
const routerFileContent = Mustache.render(this.template, moustacheViewForMain);
await writeToFile(folderPath, "main.go", routerFileContent);
};