@limlabs/limo
Version:
Infrastructure as Code generator
178 lines (177 loc) • 7.26 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getInputPrompts = exports.parseInputSchema = exports.BaseTemplate = void 0;
const zod_1 = __importDefault(require("zod"));
const yaml_1 = require("./yaml");
const node_fs_1 = require("node:fs");
class BaseTemplate {
constructor(name, directory, resourceGroupType, dirname = __dirname) {
this.scripts = {};
this.name = name;
this.directory = directory;
this.resourceGroupType = resourceGroupType;
this.data = {};
const templatePath = `${dirname}/template.yaml`;
if ((0, node_fs_1.existsSync)(templatePath)) {
this.inputSchema = parseInputSchema((0, node_fs_1.readFileSync)(templatePath, "utf-8"));
}
}
collectInputs(inputs) {
return __awaiter(this, void 0, void 0, function* () {
if (typeof this.inputSchema === "undefined") {
throw new Error("Error parsing input schema");
}
this.data = this.inputSchema.parse(inputs);
});
}
dependsOn() {
return __awaiter(this, void 0, void 0, function* () {
return { files: [], packages: [] };
});
}
generate() {
return __awaiter(this, void 0, void 0, function* () {
throw new Error("Method not implemented.");
});
}
destroy() {
return __awaiter(this, void 0, void 0, function* () {
throw new Error("Method not implemented.");
});
}
envPull(options) {
return __awaiter(this, void 0, void 0, function* () {
throw new Error("Method not implemented.");
});
}
}
exports.BaseTemplate = BaseTemplate;
BaseTemplate.resourceGroupsSupported = [];
function parseInputSchema(template) {
const data = (0, yaml_1.parseYaml)(template);
if (!data || typeof data !== "object") {
return;
}
if (!data["inputs"] || !Array.isArray(data["inputs"])) {
return;
}
const inputSchema = zod_1.default.object({
name: zod_1.default.string(),
description: zod_1.default.string(),
required: zod_1.default.boolean().optional().default(false),
default: zod_1.default.any().optional(),
type: zod_1.default.enum(["text", "number", "bool", "choice"]),
choices: zod_1.default
.array(zod_1.default.object({
name: zod_1.default.string(),
value: zod_1.default.string()
}))
.optional()
});
const inputs = data.inputs.map((input) => {
return inputSchema.parse(input);
});
let resultSchema = zod_1.default.object({});
inputs.forEach((input) => {
var _a;
let type;
switch (input.type) {
case "text":
type = input.required ? zod_1.default.string() : zod_1.default.string().optional();
if (input.default) {
type = type.default(input.default);
}
break;
case "number":
type = input.required ? zod_1.default.number() : zod_1.default.number().optional();
if (input.default) {
type = type.default(input.default);
}
break;
case "bool":
type = input.required ? zod_1.default.boolean() : zod_1.default.boolean().optional();
if (input.default) {
type = type.default(input.default);
}
break;
case "choice":
if (!input.choices) {
throw new Error("Choice input must have choices");
}
const choices = input.choices.map((choice) => choice.value);
// @ts-ignore - allow enums from dynamic string array
type = zod_1.default.enum(choices);
if (!input.required) {
type = type.optional();
}
if (input.default) {
type = type.default(input.default);
}
break;
}
type = type.describe((_a = input.description) !== null && _a !== void 0 ? _a : "unknown");
const newSchema = { [input.name]: type };
resultSchema = resultSchema.merge(zod_1.default.object(newSchema));
});
return resultSchema;
}
exports.parseInputSchema = parseInputSchema;
function getInputPrompts(schema) {
return __awaiter(this, void 0, void 0, function* () {
// loop over properties in schema and prompt user for input
const allPrompts = Object.keys(schema.shape).map((key) => {
const shape = schema.shape;
const prop = shape[key];
let type = prop._def.typeName;
let propChoices = [];
let defaultValue = type === "ZodString" ? "" : type === "ZodNumber" ? -1 : false;
if (type === "ZodEnum") {
propChoices = prop._def.values;
}
if (type === "ZodOptional" || type === "ZodDefault") {
if (type === "ZodDefault") {
defaultValue = prop._def.defaultValue();
}
type = prop._def.innerType._def.typeName;
if (type === "ZodEnum") {
propChoices = prop._def.innerType._def.values;
}
}
if (type === "ZodEnum" && propChoices.length > 0 && defaultValue) {
defaultValue = propChoices.indexOf(defaultValue);
}
let promptType = type === "ZodString"
? "text"
: type === "ZodNumber"
? "number"
: "confirm";
if (type === "ZodEnum") {
promptType = "select";
}
const choices = promptType === "select"
? {
choices: propChoices.map((value) => {
return { title: value, value: value };
})
}
: {};
const initialValue = !defaultValue ? {} : { initial: defaultValue };
const result = Object.assign(Object.assign({ type: promptType, name: key, message: prop._def.description }, initialValue), choices);
return result;
});
return allPrompts;
});
}
exports.getInputPrompts = getInputPrompts;