henotic-cli
Version:
Henotic CLI is the ultimate multi-language backend generator, accelerating development with modular project structures and smart CRUD generation. Streamline your workflow from day one!
13,885 lines • 443 kB
JavaScript
#!/usr/bin/env bun
// @bun
var __create = Object.create;
var __getProtoOf = Object.getPrototypeOf;
var __defProp = Object.defineProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __toESM = (mod, isNodeMode, target) => {
target = mod != null ? __create(__getProtoOf(mod)) : {};
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
for (let key of __getOwnPropNames(mod))
if (!__hasOwnProp.call(to, key))
__defProp(to, key, {
get: () => mod[key],
enumerable: true
});
return to;
};
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, {
get: all[name],
enumerable: true,
configurable: true,
set: (newValue) => all[name] = () => newValue
});
};
var __require = import.meta.require;
// node_modules/kleur/index.js
var require_kleur = __commonJS((exports, module) => {
var { FORCE_COLOR, NODE_DISABLE_COLORS, TERM } = process.env;
var $ = {
enabled: !NODE_DISABLE_COLORS && TERM !== "dumb" && FORCE_COLOR !== "0",
reset: init(0, 0),
bold: init(1, 22),
dim: init(2, 22),
italic: init(3, 23),
underline: init(4, 24),
inverse: init(7, 27),
hidden: init(8, 28),
strikethrough: init(9, 29),
black: init(30, 39),
red: init(31, 39),
green: init(32, 39),
yellow: init(33, 39),
blue: init(34, 39),
magenta: init(35, 39),
cyan: init(36, 39),
white: init(37, 39),
gray: init(90, 39),
grey: init(90, 39),
bgBlack: init(40, 49),
bgRed: init(41, 49),
bgGreen: init(42, 49),
bgYellow: init(43, 49),
bgBlue: init(44, 49),
bgMagenta: init(45, 49),
bgCyan: init(46, 49),
bgWhite: init(47, 49)
};
function run(arr, str) {
let i = 0, tmp, beg = "", end = "";
for (;i < arr.length; i++) {
tmp = arr[i];
beg += tmp.open;
end += tmp.close;
if (str.includes(tmp.close)) {
str = str.replace(tmp.rgx, tmp.close + tmp.open);
}
}
return beg + str + end;
}
function chain(has, keys) {
let ctx = { has, keys };
ctx.reset = $.reset.bind(ctx);
ctx.bold = $.bold.bind(ctx);
ctx.dim = $.dim.bind(ctx);
ctx.italic = $.italic.bind(ctx);
ctx.underline = $.underline.bind(ctx);
ctx.inverse = $.inverse.bind(ctx);
ctx.hidden = $.hidden.bind(ctx);
ctx.strikethrough = $.strikethrough.bind(ctx);
ctx.black = $.black.bind(ctx);
ctx.red = $.red.bind(ctx);
ctx.green = $.green.bind(ctx);
ctx.yellow = $.yellow.bind(ctx);
ctx.blue = $.blue.bind(ctx);
ctx.magenta = $.magenta.bind(ctx);
ctx.cyan = $.cyan.bind(ctx);
ctx.white = $.white.bind(ctx);
ctx.gray = $.gray.bind(ctx);
ctx.grey = $.grey.bind(ctx);
ctx.bgBlack = $.bgBlack.bind(ctx);
ctx.bgRed = $.bgRed.bind(ctx);
ctx.bgGreen = $.bgGreen.bind(ctx);
ctx.bgYellow = $.bgYellow.bind(ctx);
ctx.bgBlue = $.bgBlue.bind(ctx);
ctx.bgMagenta = $.bgMagenta.bind(ctx);
ctx.bgCyan = $.bgCyan.bind(ctx);
ctx.bgWhite = $.bgWhite.bind(ctx);
return ctx;
}
function init(open, close) {
let blk = {
open: `\x1B[${open}m`,
close: `\x1B[${close}m`,
rgx: new RegExp(`\\x1b\\[${close}m`, "g")
};
return function(txt) {
if (this !== undefined && this.has !== undefined) {
this.has.includes(open) || (this.has.push(open), this.keys.push(blk));
return txt === undefined ? this : $.enabled ? run(this.keys, txt + "") : txt + "";
}
return txt === undefined ? chain([open], [blk]) : $.enabled ? run([blk], txt + "") : txt + "";
};
}
module.exports = $;
});
// node_modules/prompts/dist/util/action.js
var require_action = __commonJS((exports, module) => {
module.exports = (key, isSelect) => {
if (key.meta && key.name !== "escape")
return;
if (key.ctrl) {
if (key.name === "a")
return "first";
if (key.name === "c")
return "abort";
if (key.name === "d")
return "abort";
if (key.name === "e")
return "last";
if (key.name === "g")
return "reset";
}
if (isSelect) {
if (key.name === "j")
return "down";
if (key.name === "k")
return "up";
}
if (key.name === "return")
return "submit";
if (key.name === "enter")
return "submit";
if (key.name === "backspace")
return "delete";
if (key.name === "delete")
return "deleteForward";
if (key.name === "abort")
return "abort";
if (key.name === "escape")
return "exit";
if (key.name === "tab")
return "next";
if (key.name === "pagedown")
return "nextPage";
if (key.name === "pageup")
return "prevPage";
if (key.name === "home")
return "home";
if (key.name === "end")
return "end";
if (key.name === "up")
return "up";
if (key.name === "down")
return "down";
if (key.name === "right")
return "right";
if (key.name === "left")
return "left";
return false;
};
});
// node_modules/prompts/dist/util/strip.js
var require_strip = __commonJS((exports, module) => {
module.exports = (str) => {
const pattern = ["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)", "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))"].join("|");
const RGX = new RegExp(pattern, "g");
return typeof str === "string" ? str.replace(RGX, "") : str;
};
});
// node_modules/sisteransi/src/index.js
var require_src = __commonJS((exports, module) => {
var ESC = "\x1B";
var CSI = `${ESC}[`;
var beep = "\x07";
var cursor = {
to(x, y) {
if (!y)
return `${CSI}${x + 1}G`;
return `${CSI}${y + 1};${x + 1}H`;
},
move(x, y) {
let ret = "";
if (x < 0)
ret += `${CSI}${-x}D`;
else if (x > 0)
ret += `${CSI}${x}C`;
if (y < 0)
ret += `${CSI}${-y}A`;
else if (y > 0)
ret += `${CSI}${y}B`;
return ret;
},
up: (count = 1) => `${CSI}${count}A`,
down: (count = 1) => `${CSI}${count}B`,
forward: (count = 1) => `${CSI}${count}C`,
backward: (count = 1) => `${CSI}${count}D`,
nextLine: (count = 1) => `${CSI}E`.repeat(count),
prevLine: (count = 1) => `${CSI}F`.repeat(count),
left: `${CSI}G`,
hide: `${CSI}?25l`,
show: `${CSI}?25h`,
save: `${ESC}7`,
restore: `${ESC}8`
};
var scroll = {
up: (count = 1) => `${CSI}S`.repeat(count),
down: (count = 1) => `${CSI}T`.repeat(count)
};
var erase = {
screen: `${CSI}2J`,
up: (count = 1) => `${CSI}1J`.repeat(count),
down: (count = 1) => `${CSI}J`.repeat(count),
line: `${CSI}2K`,
lineEnd: `${CSI}K`,
lineStart: `${CSI}1K`,
lines(count) {
let clear = "";
for (let i = 0;i < count; i++)
clear += this.line + (i < count - 1 ? cursor.up() : "");
if (count)
clear += cursor.left;
return clear;
}
};
module.exports = { cursor, scroll, erase, beep };
});
// node_modules/prompts/dist/util/clear.js
var require_clear = __commonJS((exports, module) => {
function _createForOfIteratorHelper(o, allowArrayLike) {
var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
if (!it) {
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
if (it)
o = it;
var i = 0;
var F = function F() {};
return { s: F, n: function n() {
if (i >= o.length)
return { done: true };
return { done: false, value: o[i++] };
}, e: function e(_e) {
throw _e;
}, f: F };
}
throw new TypeError(`Invalid attempt to iterate non-iterable instance.
In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`);
}
var normalCompletion = true, didErr = false, err;
return { s: function s() {
it = it.call(o);
}, n: function n() {
var step = it.next();
normalCompletion = step.done;
return step;
}, e: function e(_e2) {
didErr = true;
err = _e2;
}, f: function f() {
try {
if (!normalCompletion && it.return != null)
it.return();
} finally {
if (didErr)
throw err;
}
} };
}
function _unsupportedIterableToArray(o, minLen) {
if (!o)
return;
if (typeof o === "string")
return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor)
n = o.constructor.name;
if (n === "Map" || n === "Set")
return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))
return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length)
len = arr.length;
for (var i = 0, arr2 = new Array(len);i < len; i++)
arr2[i] = arr[i];
return arr2;
}
var strip = require_strip();
var _require = require_src();
var erase = _require.erase;
var cursor = _require.cursor;
var width = (str) => [...strip(str)].length;
module.exports = function(prompt, perLine) {
if (!perLine)
return erase.line + cursor.to(0);
let rows = 0;
const lines = prompt.split(/\r?\n/);
var _iterator = _createForOfIteratorHelper(lines), _step;
try {
for (_iterator.s();!(_step = _iterator.n()).done; ) {
let line = _step.value;
rows += 1 + Math.floor(Math.max(width(line) - 1, 0) / perLine);
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
return erase.lines(rows);
};
});
// node_modules/prompts/dist/util/figures.js
var require_figures = __commonJS((exports, module) => {
var main = {
arrowUp: "\u2191",
arrowDown: "\u2193",
arrowLeft: "\u2190",
arrowRight: "\u2192",
radioOn: "\u25C9",
radioOff: "\u25EF",
tick: "\u2714",
cross: "\u2716",
ellipsis: "\u2026",
pointerSmall: "\u203A",
line: "\u2500",
pointer: "\u276F"
};
var win = {
arrowUp: main.arrowUp,
arrowDown: main.arrowDown,
arrowLeft: main.arrowLeft,
arrowRight: main.arrowRight,
radioOn: "(*)",
radioOff: "( )",
tick: "\u221A",
cross: "\xD7",
ellipsis: "...",
pointerSmall: "\xBB",
line: "\u2500",
pointer: ">"
};
var figures = process.platform === "win32" ? win : main;
module.exports = figures;
});
// node_modules/prompts/dist/util/style.js
var require_style = __commonJS((exports, module) => {
var c = require_kleur();
var figures = require_figures();
var styles3 = Object.freeze({
password: {
scale: 1,
render: (input) => "*".repeat(input.length)
},
emoji: {
scale: 2,
render: (input) => "\uD83D\uDE03".repeat(input.length)
},
invisible: {
scale: 0,
render: (input) => ""
},
default: {
scale: 1,
render: (input) => `${input}`
}
});
var render = (type) => styles3[type] || styles3.default;
var symbols = Object.freeze({
aborted: c.red(figures.cross),
done: c.green(figures.tick),
exited: c.yellow(figures.cross),
default: c.cyan("?")
});
var symbol = (done, aborted, exited) => aborted ? symbols.aborted : exited ? symbols.exited : done ? symbols.done : symbols.default;
var delimiter = (completing) => c.gray(completing ? figures.ellipsis : figures.pointerSmall);
var item = (expandable, expanded) => c.gray(expandable ? expanded ? figures.pointerSmall : "+" : figures.line);
module.exports = {
styles: styles3,
render,
symbols,
symbol,
delimiter,
item
};
});
// node_modules/prompts/dist/util/lines.js
var require_lines = __commonJS((exports, module) => {
var strip = require_strip();
module.exports = function(msg, perLine) {
let lines = String(strip(msg) || "").split(/\r?\n/);
if (!perLine)
return lines.length;
return lines.map((l) => Math.ceil(l.length / perLine)).reduce((a, b) => a + b);
};
});
// node_modules/prompts/dist/util/wrap.js
var require_wrap = __commonJS((exports, module) => {
module.exports = (msg, opts = {}) => {
const tab = Number.isSafeInteger(parseInt(opts.margin)) ? new Array(parseInt(opts.margin)).fill(" ").join("") : opts.margin || "";
const width = opts.width;
return (msg || "").split(/\r?\n/g).map((line) => line.split(/\s+/g).reduce((arr, w) => {
if (w.length + tab.length >= width || arr[arr.length - 1].length + w.length + 1 < width)
arr[arr.length - 1] += ` ${w}`;
else
arr.push(`${tab}${w}`);
return arr;
}, [tab]).join(`
`)).join(`
`);
};
});
// node_modules/prompts/dist/util/entriesToDisplay.js
var require_entriesToDisplay = __commonJS((exports, module) => {
module.exports = (cursor, total, maxVisible) => {
maxVisible = maxVisible || total;
let startIndex = Math.min(total - maxVisible, cursor - Math.floor(maxVisible / 2));
if (startIndex < 0)
startIndex = 0;
let endIndex = Math.min(startIndex + maxVisible, total);
return {
startIndex,
endIndex
};
};
});
// node_modules/prompts/dist/util/index.js
var require_util = __commonJS((exports, module) => {
module.exports = {
action: require_action(),
clear: require_clear(),
style: require_style(),
strip: require_strip(),
figures: require_figures(),
lines: require_lines(),
wrap: require_wrap(),
entriesToDisplay: require_entriesToDisplay()
};
});
// node_modules/prompts/dist/elements/prompt.js
var require_prompt = __commonJS((exports, module) => {
var readline = __require("readline");
var _require = require_util();
var action = _require.action;
var EventEmitter = __require("events");
var _require2 = require_src();
var beep = _require2.beep;
var cursor = _require2.cursor;
var color = require_kleur();
class Prompt extends EventEmitter {
constructor(opts = {}) {
super();
this.firstRender = true;
this.in = opts.stdin || process.stdin;
this.out = opts.stdout || process.stdout;
this.onRender = (opts.onRender || (() => {
return;
})).bind(this);
const rl = readline.createInterface({
input: this.in,
escapeCodeTimeout: 50
});
readline.emitKeypressEvents(this.in, rl);
if (this.in.isTTY)
this.in.setRawMode(true);
const isSelect = ["SelectPrompt", "MultiselectPrompt"].indexOf(this.constructor.name) > -1;
const keypress = (str, key) => {
let a = action(key, isSelect);
if (a === false) {
this._ && this._(str, key);
} else if (typeof this[a] === "function") {
this[a](key);
} else {
this.bell();
}
};
this.close = () => {
this.out.write(cursor.show);
this.in.removeListener("keypress", keypress);
if (this.in.isTTY)
this.in.setRawMode(false);
rl.close();
this.emit(this.aborted ? "abort" : this.exited ? "exit" : "submit", this.value);
this.closed = true;
};
this.in.on("keypress", keypress);
}
fire() {
this.emit("state", {
value: this.value,
aborted: !!this.aborted,
exited: !!this.exited
});
}
bell() {
this.out.write(beep);
}
render() {
this.onRender(color);
if (this.firstRender)
this.firstRender = false;
}
}
module.exports = Prompt;
});
// node_modules/prompts/dist/elements/text.js
var require_text = __commonJS((exports, module) => {
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _asyncToGenerator(fn) {
return function() {
var self = this, args = arguments;
return new Promise(function(resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
var color = require_kleur();
var Prompt = require_prompt();
var _require = require_src();
var erase = _require.erase;
var cursor = _require.cursor;
var _require2 = require_util();
var style = _require2.style;
var clear = _require2.clear;
var lines = _require2.lines;
var figures = _require2.figures;
class TextPrompt extends Prompt {
constructor(opts = {}) {
super(opts);
this.transform = style.render(opts.style);
this.scale = this.transform.scale;
this.msg = opts.message;
this.initial = opts.initial || ``;
this.validator = opts.validate || (() => true);
this.value = ``;
this.errorMsg = opts.error || `Please Enter A Valid Value`;
this.cursor = Number(!!this.initial);
this.cursorOffset = 0;
this.clear = clear(``, this.out.columns);
this.render();
}
set value(v) {
if (!v && this.initial) {
this.placeholder = true;
this.rendered = color.gray(this.transform.render(this.initial));
} else {
this.placeholder = false;
this.rendered = this.transform.render(v);
}
this._value = v;
this.fire();
}
get value() {
return this._value;
}
reset() {
this.value = ``;
this.cursor = Number(!!this.initial);
this.cursorOffset = 0;
this.fire();
this.render();
}
exit() {
this.abort();
}
abort() {
this.value = this.value || this.initial;
this.done = this.aborted = true;
this.error = false;
this.red = false;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
validate() {
var _this = this;
return _asyncToGenerator(function* () {
let valid = yield _this.validator(_this.value);
if (typeof valid === `string`) {
_this.errorMsg = valid;
valid = false;
}
_this.error = !valid;
})();
}
submit() {
var _this2 = this;
return _asyncToGenerator(function* () {
_this2.value = _this2.value || _this2.initial;
_this2.cursorOffset = 0;
_this2.cursor = _this2.rendered.length;
yield _this2.validate();
if (_this2.error) {
_this2.red = true;
_this2.fire();
_this2.render();
return;
}
_this2.done = true;
_this2.aborted = false;
_this2.fire();
_this2.render();
_this2.out.write(`
`);
_this2.close();
})();
}
next() {
if (!this.placeholder)
return this.bell();
this.value = this.initial;
this.cursor = this.rendered.length;
this.fire();
this.render();
}
moveCursor(n) {
if (this.placeholder)
return;
this.cursor = this.cursor + n;
this.cursorOffset += n;
}
_(c, key) {
let s1 = this.value.slice(0, this.cursor);
let s2 = this.value.slice(this.cursor);
this.value = `${s1}${c}${s2}`;
this.red = false;
this.cursor = this.placeholder ? 0 : s1.length + 1;
this.render();
}
delete() {
if (this.isCursorAtStart())
return this.bell();
let s1 = this.value.slice(0, this.cursor - 1);
let s2 = this.value.slice(this.cursor);
this.value = `${s1}${s2}`;
this.red = false;
if (this.isCursorAtStart()) {
this.cursorOffset = 0;
} else {
this.cursorOffset++;
this.moveCursor(-1);
}
this.render();
}
deleteForward() {
if (this.cursor * this.scale >= this.rendered.length || this.placeholder)
return this.bell();
let s1 = this.value.slice(0, this.cursor);
let s2 = this.value.slice(this.cursor + 1);
this.value = `${s1}${s2}`;
this.red = false;
if (this.isCursorAtEnd()) {
this.cursorOffset = 0;
} else {
this.cursorOffset++;
}
this.render();
}
first() {
this.cursor = 0;
this.render();
}
last() {
this.cursor = this.value.length;
this.render();
}
left() {
if (this.cursor <= 0 || this.placeholder)
return this.bell();
this.moveCursor(-1);
this.render();
}
right() {
if (this.cursor * this.scale >= this.rendered.length || this.placeholder)
return this.bell();
this.moveCursor(1);
this.render();
}
isCursorAtStart() {
return this.cursor === 0 || this.placeholder && this.cursor === 1;
}
isCursorAtEnd() {
return this.cursor === this.rendered.length || this.placeholder && this.cursor === this.rendered.length + 1;
}
render() {
if (this.closed)
return;
if (!this.firstRender) {
if (this.outputError)
this.out.write(cursor.down(lines(this.outputError, this.out.columns) - 1) + clear(this.outputError, this.out.columns));
this.out.write(clear(this.outputText, this.out.columns));
}
super.render();
this.outputError = "";
this.outputText = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(this.done), this.red ? color.red(this.rendered) : this.rendered].join(` `);
if (this.error) {
this.outputError += this.errorMsg.split(`
`).reduce((a, l, i) => a + `
${i ? " " : figures.pointerSmall} ${color.red().italic(l)}`, ``);
}
this.out.write(erase.line + cursor.to(0) + this.outputText + cursor.save + this.outputError + cursor.restore + cursor.move(this.cursorOffset, 0));
}
}
module.exports = TextPrompt;
});
// node_modules/prompts/dist/elements/select.js
var require_select = __commonJS((exports, module) => {
var color = require_kleur();
var Prompt = require_prompt();
var _require = require_util();
var style = _require.style;
var clear = _require.clear;
var figures = _require.figures;
var wrap = _require.wrap;
var entriesToDisplay = _require.entriesToDisplay;
var _require2 = require_src();
var cursor = _require2.cursor;
class SelectPrompt extends Prompt {
constructor(opts = {}) {
super(opts);
this.msg = opts.message;
this.hint = opts.hint || "- Use arrow-keys. Return to submit.";
this.warn = opts.warn || "- This option is disabled";
this.cursor = opts.initial || 0;
this.choices = opts.choices.map((ch, idx) => {
if (typeof ch === "string")
ch = {
title: ch,
value: idx
};
return {
title: ch && (ch.title || ch.value || ch),
value: ch && (ch.value === undefined ? idx : ch.value),
description: ch && ch.description,
selected: ch && ch.selected,
disabled: ch && ch.disabled
};
});
this.optionsPerPage = opts.optionsPerPage || 10;
this.value = (this.choices[this.cursor] || {}).value;
this.clear = clear("", this.out.columns);
this.render();
}
moveCursor(n) {
this.cursor = n;
this.value = this.choices[n].value;
this.fire();
}
reset() {
this.moveCursor(0);
this.fire();
this.render();
}
exit() {
this.abort();
}
abort() {
this.done = this.aborted = true;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
submit() {
if (!this.selection.disabled) {
this.done = true;
this.aborted = false;
this.fire();
this.render();
this.out.write(`
`);
this.close();
} else
this.bell();
}
first() {
this.moveCursor(0);
this.render();
}
last() {
this.moveCursor(this.choices.length - 1);
this.render();
}
up() {
if (this.cursor === 0) {
this.moveCursor(this.choices.length - 1);
} else {
this.moveCursor(this.cursor - 1);
}
this.render();
}
down() {
if (this.cursor === this.choices.length - 1) {
this.moveCursor(0);
} else {
this.moveCursor(this.cursor + 1);
}
this.render();
}
next() {
this.moveCursor((this.cursor + 1) % this.choices.length);
this.render();
}
_(c, key) {
if (c === " ")
return this.submit();
}
get selection() {
return this.choices[this.cursor];
}
render() {
if (this.closed)
return;
if (this.firstRender)
this.out.write(cursor.hide);
else
this.out.write(clear(this.outputText, this.out.columns));
super.render();
let _entriesToDisplay = entriesToDisplay(this.cursor, this.choices.length, this.optionsPerPage), startIndex = _entriesToDisplay.startIndex, endIndex = _entriesToDisplay.endIndex;
this.outputText = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(false), this.done ? this.selection.title : this.selection.disabled ? color.yellow(this.warn) : color.gray(this.hint)].join(" ");
if (!this.done) {
this.outputText += `
`;
for (let i = startIndex;i < endIndex; i++) {
let title, prefix, desc = "", v = this.choices[i];
if (i === startIndex && startIndex > 0) {
prefix = figures.arrowUp;
} else if (i === endIndex - 1 && endIndex < this.choices.length) {
prefix = figures.arrowDown;
} else {
prefix = " ";
}
if (v.disabled) {
title = this.cursor === i ? color.gray().underline(v.title) : color.strikethrough().gray(v.title);
prefix = (this.cursor === i ? color.bold().gray(figures.pointer) + " " : " ") + prefix;
} else {
title = this.cursor === i ? color.cyan().underline(v.title) : v.title;
prefix = (this.cursor === i ? color.cyan(figures.pointer) + " " : " ") + prefix;
if (v.description && this.cursor === i) {
desc = ` - ${v.description}`;
if (prefix.length + title.length + desc.length >= this.out.columns || v.description.split(/\r?\n/).length > 1) {
desc = `
` + wrap(v.description, {
margin: 3,
width: this.out.columns
});
}
}
}
this.outputText += `${prefix} ${title}${color.gray(desc)}
`;
}
}
this.out.write(this.outputText);
}
}
module.exports = SelectPrompt;
});
// node_modules/prompts/dist/elements/toggle.js
var require_toggle = __commonJS((exports, module) => {
var color = require_kleur();
var Prompt = require_prompt();
var _require = require_util();
var style = _require.style;
var clear = _require.clear;
var _require2 = require_src();
var cursor = _require2.cursor;
var erase = _require2.erase;
class TogglePrompt extends Prompt {
constructor(opts = {}) {
super(opts);
this.msg = opts.message;
this.value = !!opts.initial;
this.active = opts.active || "on";
this.inactive = opts.inactive || "off";
this.initialValue = this.value;
this.render();
}
reset() {
this.value = this.initialValue;
this.fire();
this.render();
}
exit() {
this.abort();
}
abort() {
this.done = this.aborted = true;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
submit() {
this.done = true;
this.aborted = false;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
deactivate() {
if (this.value === false)
return this.bell();
this.value = false;
this.render();
}
activate() {
if (this.value === true)
return this.bell();
this.value = true;
this.render();
}
delete() {
this.deactivate();
}
left() {
this.deactivate();
}
right() {
this.activate();
}
down() {
this.deactivate();
}
up() {
this.activate();
}
next() {
this.value = !this.value;
this.fire();
this.render();
}
_(c, key) {
if (c === " ") {
this.value = !this.value;
} else if (c === "1") {
this.value = true;
} else if (c === "0") {
this.value = false;
} else
return this.bell();
this.render();
}
render() {
if (this.closed)
return;
if (this.firstRender)
this.out.write(cursor.hide);
else
this.out.write(clear(this.outputText, this.out.columns));
super.render();
this.outputText = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(this.done), this.value ? this.inactive : color.cyan().underline(this.inactive), color.gray("/"), this.value ? color.cyan().underline(this.active) : this.active].join(" ");
this.out.write(erase.line + cursor.to(0) + this.outputText);
}
}
module.exports = TogglePrompt;
});
// node_modules/prompts/dist/dateparts/datepart.js
var require_datepart = __commonJS((exports, module) => {
class DatePart {
constructor({
token,
date,
parts,
locales
}) {
this.token = token;
this.date = date || new Date;
this.parts = parts || [this];
this.locales = locales || {};
}
up() {}
down() {}
next() {
const currentIdx = this.parts.indexOf(this);
return this.parts.find((part, idx) => idx > currentIdx && part instanceof DatePart);
}
setTo(val) {}
prev() {
let parts = [].concat(this.parts).reverse();
const currentIdx = parts.indexOf(this);
return parts.find((part, idx) => idx > currentIdx && part instanceof DatePart);
}
toString() {
return String(this.date);
}
}
module.exports = DatePart;
});
// node_modules/prompts/dist/dateparts/meridiem.js
var require_meridiem = __commonJS((exports, module) => {
var DatePart = require_datepart();
class Meridiem extends DatePart {
constructor(opts = {}) {
super(opts);
}
up() {
this.date.setHours((this.date.getHours() + 12) % 24);
}
down() {
this.up();
}
toString() {
let meridiem = this.date.getHours() > 12 ? "pm" : "am";
return /\A/.test(this.token) ? meridiem.toUpperCase() : meridiem;
}
}
module.exports = Meridiem;
});
// node_modules/prompts/dist/dateparts/day.js
var require_day = __commonJS((exports, module) => {
var DatePart = require_datepart();
var pos = (n) => {
n = n % 10;
return n === 1 ? "st" : n === 2 ? "nd" : n === 3 ? "rd" : "th";
};
class Day extends DatePart {
constructor(opts = {}) {
super(opts);
}
up() {
this.date.setDate(this.date.getDate() + 1);
}
down() {
this.date.setDate(this.date.getDate() - 1);
}
setTo(val) {
this.date.setDate(parseInt(val.substr(-2)));
}
toString() {
let date = this.date.getDate();
let day = this.date.getDay();
return this.token === "DD" ? String(date).padStart(2, "0") : this.token === "Do" ? date + pos(date) : this.token === "d" ? day + 1 : this.token === "ddd" ? this.locales.weekdaysShort[day] : this.token === "dddd" ? this.locales.weekdays[day] : date;
}
}
module.exports = Day;
});
// node_modules/prompts/dist/dateparts/hours.js
var require_hours = __commonJS((exports, module) => {
var DatePart = require_datepart();
class Hours extends DatePart {
constructor(opts = {}) {
super(opts);
}
up() {
this.date.setHours(this.date.getHours() + 1);
}
down() {
this.date.setHours(this.date.getHours() - 1);
}
setTo(val) {
this.date.setHours(parseInt(val.substr(-2)));
}
toString() {
let hours = this.date.getHours();
if (/h/.test(this.token))
hours = hours % 12 || 12;
return this.token.length > 1 ? String(hours).padStart(2, "0") : hours;
}
}
module.exports = Hours;
});
// node_modules/prompts/dist/dateparts/milliseconds.js
var require_milliseconds = __commonJS((exports, module) => {
var DatePart = require_datepart();
class Milliseconds extends DatePart {
constructor(opts = {}) {
super(opts);
}
up() {
this.date.setMilliseconds(this.date.getMilliseconds() + 1);
}
down() {
this.date.setMilliseconds(this.date.getMilliseconds() - 1);
}
setTo(val) {
this.date.setMilliseconds(parseInt(val.substr(-this.token.length)));
}
toString() {
return String(this.date.getMilliseconds()).padStart(4, "0").substr(0, this.token.length);
}
}
module.exports = Milliseconds;
});
// node_modules/prompts/dist/dateparts/minutes.js
var require_minutes = __commonJS((exports, module) => {
var DatePart = require_datepart();
class Minutes extends DatePart {
constructor(opts = {}) {
super(opts);
}
up() {
this.date.setMinutes(this.date.getMinutes() + 1);
}
down() {
this.date.setMinutes(this.date.getMinutes() - 1);
}
setTo(val) {
this.date.setMinutes(parseInt(val.substr(-2)));
}
toString() {
let m = this.date.getMinutes();
return this.token.length > 1 ? String(m).padStart(2, "0") : m;
}
}
module.exports = Minutes;
});
// node_modules/prompts/dist/dateparts/month.js
var require_month = __commonJS((exports, module) => {
var DatePart = require_datepart();
class Month extends DatePart {
constructor(opts = {}) {
super(opts);
}
up() {
this.date.setMonth(this.date.getMonth() + 1);
}
down() {
this.date.setMonth(this.date.getMonth() - 1);
}
setTo(val) {
val = parseInt(val.substr(-2)) - 1;
this.date.setMonth(val < 0 ? 0 : val);
}
toString() {
let month = this.date.getMonth();
let tl = this.token.length;
return tl === 2 ? String(month + 1).padStart(2, "0") : tl === 3 ? this.locales.monthsShort[month] : tl === 4 ? this.locales.months[month] : String(month + 1);
}
}
module.exports = Month;
});
// node_modules/prompts/dist/dateparts/seconds.js
var require_seconds = __commonJS((exports, module) => {
var DatePart = require_datepart();
class Seconds extends DatePart {
constructor(opts = {}) {
super(opts);
}
up() {
this.date.setSeconds(this.date.getSeconds() + 1);
}
down() {
this.date.setSeconds(this.date.getSeconds() - 1);
}
setTo(val) {
this.date.setSeconds(parseInt(val.substr(-2)));
}
toString() {
let s = this.date.getSeconds();
return this.token.length > 1 ? String(s).padStart(2, "0") : s;
}
}
module.exports = Seconds;
});
// node_modules/prompts/dist/dateparts/year.js
var require_year = __commonJS((exports, module) => {
var DatePart = require_datepart();
class Year extends DatePart {
constructor(opts = {}) {
super(opts);
}
up() {
this.date.setFullYear(this.date.getFullYear() + 1);
}
down() {
this.date.setFullYear(this.date.getFullYear() - 1);
}
setTo(val) {
this.date.setFullYear(val.substr(-4));
}
toString() {
let year = String(this.date.getFullYear()).padStart(4, "0");
return this.token.length === 2 ? year.substr(-2) : year;
}
}
module.exports = Year;
});
// node_modules/prompts/dist/dateparts/index.js
var require_dateparts = __commonJS((exports, module) => {
module.exports = {
DatePart: require_datepart(),
Meridiem: require_meridiem(),
Day: require_day(),
Hours: require_hours(),
Milliseconds: require_milliseconds(),
Minutes: require_minutes(),
Month: require_month(),
Seconds: require_seconds(),
Year: require_year()
};
});
// node_modules/prompts/dist/elements/date.js
var require_date = __commonJS((exports, module) => {
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _asyncToGenerator(fn) {
return function() {
var self = this, args = arguments;
return new Promise(function(resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
var color = require_kleur();
var Prompt = require_prompt();
var _require = require_util();
var style = _require.style;
var clear = _require.clear;
var figures = _require.figures;
var _require2 = require_src();
var erase = _require2.erase;
var cursor = _require2.cursor;
var _require3 = require_dateparts();
var DatePart = _require3.DatePart;
var Meridiem = _require3.Meridiem;
var Day = _require3.Day;
var Hours = _require3.Hours;
var Milliseconds = _require3.Milliseconds;
var Minutes = _require3.Minutes;
var Month = _require3.Month;
var Seconds = _require3.Seconds;
var Year = _require3.Year;
var regex = /\\(.)|"((?:\\["\\]|[^"])+)"|(D[Do]?|d{3,4}|d)|(M{1,4})|(YY(?:YY)?)|([aA])|([Hh]{1,2})|(m{1,2})|(s{1,2})|(S{1,4})|./g;
var regexGroups = {
1: ({
token
}) => token.replace(/\\(.)/g, "$1"),
2: (opts) => new Day(opts),
3: (opts) => new Month(opts),
4: (opts) => new Year(opts),
5: (opts) => new Meridiem(opts),
6: (opts) => new Hours(opts),
7: (opts) => new Minutes(opts),
8: (opts) => new Seconds(opts),
9: (opts) => new Milliseconds(opts)
};
var dfltLocales = {
months: "January,February,March,April,May,June,July,August,September,October,November,December".split(","),
monthsShort: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec".split(","),
weekdays: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday".split(","),
weekdaysShort: "Sun,Mon,Tue,Wed,Thu,Fri,Sat".split(",")
};
class DatePrompt extends Prompt {
constructor(opts = {}) {
super(opts);
this.msg = opts.message;
this.cursor = 0;
this.typed = "";
this.locales = Object.assign(dfltLocales, opts.locales);
this._date = opts.initial || new Date;
this.errorMsg = opts.error || "Please Enter A Valid Value";
this.validator = opts.validate || (() => true);
this.mask = opts.mask || "YYYY-MM-DD HH:mm:ss";
this.clear = clear("", this.out.columns);
this.render();
}
get value() {
return this.date;
}
get date() {
return this._date;
}
set date(date) {
if (date)
this._date.setTime(date.getTime());
}
set mask(mask) {
let result;
this.parts = [];
while (result = regex.exec(mask)) {
let match = result.shift();
let idx = result.findIndex((gr) => gr != null);
this.parts.push(idx in regexGroups ? regexGroups[idx]({
token: result[idx] || match,
date: this.date,
parts: this.parts,
locales: this.locales
}) : result[idx] || match);
}
let parts = this.parts.reduce((arr, i) => {
if (typeof i === "string" && typeof arr[arr.length - 1] === "string")
arr[arr.length - 1] += i;
else
arr.push(i);
return arr;
}, []);
this.parts.splice(0);
this.parts.push(...parts);
this.reset();
}
moveCursor(n) {
this.typed = "";
this.cursor = n;
this.fire();
}
reset() {
this.moveCursor(this.parts.findIndex((p) => p instanceof DatePart));
this.fire();
this.render();
}
exit() {
this.abort();
}
abort() {
this.done = this.aborted = true;
this.error = false;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
validate() {
var _this = this;
return _asyncToGenerator(function* () {
let valid = yield _this.validator(_this.value);
if (typeof valid === "string") {
_this.errorMsg = valid;
valid = false;
}
_this.error = !valid;
})();
}
submit() {
var _this2 = this;
return _asyncToGenerator(function* () {
yield _this2.validate();
if (_this2.error) {
_this2.color = "red";
_this2.fire();
_this2.render();
return;
}
_this2.done = true;
_this2.aborted = false;
_this2.fire();
_this2.render();
_this2.out.write(`
`);
_this2.close();
})();
}
up() {
this.typed = "";
this.parts[this.cursor].up();
this.render();
}
down() {
this.typed = "";
this.parts[this.cursor].down();
this.render();
}
left() {
let prev = this.parts[this.cursor].prev();
if (prev == null)
return this.bell();
this.moveCursor(this.parts.indexOf(prev));
this.render();
}
right() {
let next = this.parts[this.cursor].next();
if (next == null)
return this.bell();
this.moveCursor(this.parts.indexOf(next));
this.render();
}
next() {
let next = this.parts[this.cursor].next();
this.moveCursor(next ? this.parts.indexOf(next) : this.parts.findIndex((part) => part instanceof DatePart));
this.render();
}
_(c) {
if (/\d/.test(c)) {
this.typed += c;
this.parts[this.cursor].setTo(this.typed);
this.render();
}
}
render() {
if (this.closed)
return;
if (this.firstRender)
this.out.write(cursor.hide);
else
this.out.write(clear(this.outputText, this.out.columns));
super.render();
this.outputText = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(false), this.parts.reduce((arr, p, idx) => arr.concat(idx === this.cursor && !this.done ? color.cyan().underline(p.toString()) : p), []).join("")].join(" ");
if (this.error) {
this.outputText += this.errorMsg.split(`
`).reduce((a, l, i) => a + `
${i ? ` ` : figures.pointerSmall} ${color.red().italic(l)}`, ``);
}
this.out.write(erase.line + cursor.to(0) + this.outputText);
}
}
module.exports = DatePrompt;
});
// node_modules/prompts/dist/elements/number.js
var require_number = __commonJS((exports, module) => {
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _asyncToGenerator(fn) {
return function() {
var self = this, args = arguments;
return new Promise(function(resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
var color = require_kleur();
var Prompt = require_prompt();
var _require = require_src();
var cursor = _require.cursor;
var erase = _require.erase;
var _require2 = require_util();
var style = _require2.style;
var figures = _require2.figures;
var clear = _require2.clear;
var lines = _require2.lines;
var isNumber = /[0-9]/;
var isDef = (any) => any !== undefined;
var round = (number, precision) => {
let factor = Math.pow(10, precision);
return Math.round(number * factor) / factor;
};
class NumberPrompt extends Prompt {
constructor(opts = {}) {
super(opts);
this.transform = style.render(opts.style);
this.msg = opts.message;
this.initial = isDef(opts.initial) ? opts.initial : "";
this.float = !!opts.float;
this.round = opts.round || 2;
this.inc = opts.increment || 1;
this.min = isDef(opts.min) ? opts.min : -Infinity;
this.max = isDef(opts.max) ? opts.max : Infinity;
this.errorMsg = opts.error || `Please Enter A Valid Value`;
this.validator = opts.validate || (() => true);
this.color = `cyan`;
this.value = ``;
this.typed = ``;
this.lastHit = 0;
this.render();
}
set value(v) {
if (!v && v !== 0) {
this.placeholder = true;
this.rendered = color.gray(this.transform.render(`${this.initial}`));
this._value = ``;
} else {
this.placeholder = false;
this.rendered = this.transform.render(`${round(v, this.round)}`);
this._value = round(v, this.round);
}
this.fire();
}
get value() {
return this._value;
}
parse(x) {
return this.float ? parseFloat(x) : parseInt(x);
}
valid(c) {
return c === `-` || c === `.` && this.float || isNumber.test(c);
}
reset() {
this.typed = ``;
this.value = ``;
this.fire();
this.render();
}
exit() {
this.abort();
}
abort() {
let x = this.value;
this.value = x !== `` ? x : this.initial;
this.done = this.aborted = true;
this.error = false;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
validate() {
var _this = this;
return _asyncToGenerator(function* () {
let valid = yield _this.validator(_this.value);
if (typeof valid === `string`) {
_this.errorMsg = valid;
valid = false;
}
_this.error = !valid;
})();
}
submit() {
var _this2 = this;
return _asyncToGenerator(function* () {
yield _this2.validate();
if (_this2.error) {
_this2.color = `red`;
_this2.fire();
_this2.render();
return;
}
let x = _this2.value;
_this2.value = x !== `` ? x : _this2.initial;
_this2.done = true;
_this2.aborted = false;
_this2.error = false;
_this2.fire();
_this2.render();
_this2.out.write(`
`);
_this2.close();
})();
}
up() {
this.typed = ``;
if (this.value === "") {
this.value = this.min - this.inc;
}
if (this.value >= this.max)
return this.bell();
this.value += this.inc;
this.color = `cyan`;
this.fire();
this.render();
}
down() {
this.typed = ``;
if (this.value === "") {
this.value = this.min + this.inc;
}
if (this.value <= this.min)
return this.bell();
this.value -= this.inc;
this.color = `cyan`;
this.fire();
this.render();
}
delete() {
let val = this.value.toString();
if (val.length === 0)
return this.bell();
this.value = this.parse(val = val.slice(0, -1)) || ``;
if (this.value !== "" && this.value < this.min) {
this.value = this.min;
}
this.color = `cyan`;
this.fire();
this.render();
}
next() {
this.value = this.initial;
this.fire();
this.render();
}
_(c, key) {
if (!this.valid(c))
return this.bell();
const now = Date.now();
if (now - this.lastHit > 1000)
this.typed = ``;
this.typed += c;
this.lastHit = now;
this.color = `cyan`;
if (c === `.`)
return this.fire();
this.value = Math.min(this.parse(this.typed), this.max);
if (this.value > this.max)
this.value = this.max;
if (this.value < this.min)
this.value = this.min;
this.fire();
this.render();
}
render() {
if (this.closed)
return;
if (!this.firstRender) {
if (this.outputError)
this.out.write(cursor.down(lines(this.outputError, this.out.columns) - 1) + clear(this.outputError, this.out.columns));
this.out.write(clear(this.outputText, this.out.columns));
}
super.render();
this.outputError = "";
this.outputText = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(this.done), !this.done || !this.done && !this.placeholder ? color[this.color]().underline(this.rendered) : this.rendered].join(` `);
if (this.error) {
this.outputError += this.errorMsg.split(`
`).reduce((a, l, i) => a + `
${i ? ` ` : figures.pointerSmall} ${color.red().italic(l)}`, ``);
}
this.out.write(erase.line + cursor.to(0) + this.outputText + cursor.save + this.outputError + cursor.restore);
}
}
module.exports = NumberPrompt;
});
// node_modules/prompts/dist/elements/multiselect.js
var require_multiselect = __commonJS((exports, module) => {
var color = require_kleur();
var _require = require_src();
var cursor = _require.cursor;
var Prompt = require_prompt();
var _require2 = require_util();
var clear = _require2.clear;
var figures = _require2.figures;
var style = _require2.style;
var wrap = _require2.wrap;
var entriesToDisplay = _require2.entriesToDisplay;
class MultiselectPrompt extends Prompt {
constructor(opts = {}) {
super(opts);
this.msg = opts.message;
this.cursor = opts.cursor || 0;
this.scrollIndex = opts.cursor || 0;
this.hint = opts.hint || "";
this.warn = opts.warn || "- This option is disabled -";
this.minSelected = opts.min;
this.showMinError = false;
this.maxChoices = opts.max;
this.instructions = opts.instructions;
this.optionsPerPage = opts.optionsPerPage || 10;
this.value = opts.choices.map((ch, idx) => {
if (typeof ch === "string")
ch = {
title: ch,
value: idx
};
return {
title: ch && (ch.title || ch.value || ch),
description: ch && ch.description,
value: ch && (ch.value === undefined ? idx : ch.value),
selected: ch && ch.selected,
disabled: ch && ch.disabled
};
});
this.clear = clear("", this.out.columns);
if (!opts.overrideRender) {
this.render();
}
}
reset() {
this.value.map((v) => !v.selected);
this.cursor = 0;
this.fire();
this.render();
}
selected() {
return this.value.filter((v) => v.selected);
}
exit() {
this.abort();
}
abort() {
this.done = this.aborted = true;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
submit() {
const selected = this.value.filter((e) => e.selected);
if (this.minSelected && selected.length < this.minSelected) {
this.showMinError = true;
this.render();
} else {
this.done = true;
this.aborted = false;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
}
first() {
this.cursor = 0;
this.render();
}
last() {
this.cursor = this.value.length - 1;
this.render();
}
next() {
this.cursor = (this.cursor + 1) % this.value.length;
this.render();
}
up() {
if (this.cursor === 0) {
this.cursor = this.value.length - 1;
} else {
this.cursor--;
}
this.render();
}
down() {
if (this.cursor === this.value.length - 1) {
this.cursor = 0;
} else {
this.cursor++;
}
this.render();
}
left() {
this.value[this.cursor].selected = false;
this.render();
}
right() {
if (this.value.filter((e) => e.selected).length >= this.maxChoices)
return this.bell();
this.value[this.cursor].selected = true;
this.render();
}
handleSpaceToggle() {
const v = this.value[this.cursor];
if (v.selected) {
v.selected = false;
this.render();
} else if (v.disabled || this.value.filter((e) => e.selected).length >= this.maxChoices) {
return this.bell();
} else {
v.selected = true;
this.render();
}
}
toggleAll() {
if (this.maxChoices !== undefined || this.value[this.cursor].disabled) {
return this.bell();
}
const newSelected = !this.value[this.cursor].selected;
this.value.filter((v) => !v.disabled).forEach((v) => v.selected = newSelected);
this.render();
}
_(c, key) {
if (c === " ") {
this.handleSpaceToggle();
} else if (c === "a") {
this.toggleAll();
} else {
return this.bell();
}
}
renderInstructions() {
if (this.instructions === undefined || this.instructions) {
if (typeof this.instructions === "string") {
return this.instructions;
}
return `
Instructions:
` + ` ${figures.arrowUp}/${figures.arrowDown}: Highlight option
` + ` ${figures.arrowLeft}/${figures.arrowRight}/[space]: Toggle selection
` + (this.maxChoices === undefined ? ` a: Toggle all
` : "") + ` enter/return: Complete answer`;
}
return "";
}
renderOption(cursor2, v, i, arrowIndicator) {
const prefix = (v.selected ? color.green(figures.radioOn) : figures.radioOff) + " " + arrowIndicator + " ";
let title, desc;
if (v.disabled) {
title = cursor2 === i ? color.gray().underline(v.title) : color.strikethrough().gray(v.title);
} else {
title = cursor2 === i ? color.cyan().underline(v.title) : v.title;
if (cursor2 === i && v.description) {
desc = ` - ${v.description}`;
if (prefix.length + title.length + desc.length >= this.out.columns || v.description.split(/\r?\n/).length > 1) {
desc = `
` + wrap(v.description, {
margin: prefix.length,
width: this.out.columns
});
}
}
}
return prefix + title + color.gray(desc || "");
}
paginateOptions(options) {
if (options.length === 0) {
return color.red("No matches for this query.");
}
let _entriesToDisplay = entriesToDisplay(this.cursor, options.length, this.optionsPerPage), startIndex = _entriesToDisplay.startIndex, endIndex = _entriesToDisplay.endIndex;
let prefix, styledOptions = [];
for (let i = startIndex;i < endIndex; i++) {
if (i === startIndex && startIndex > 0) {
prefix = figures.arrowUp;
} else if (i === endIndex - 1 && endIndex < options.length) {
prefix = figures.arrowDown;
} else {
prefix = " ";
}
styledOptions.push(this.renderOption(this.cursor, options[i], i, prefix));
}
return `
` + styledOptions.join(`
`);
}
renderOptions(options) {
if (!this.done) {
return this.paginateOptions(options);
}
return "";
}
renderDoneOrInstructions() {
if (this.done) {
return this.value.filter((e) => e.selected).map((v) => v.title).join(", ");
}
const output = [color.gray(this.hint), this.renderInstructions()];
if (this.value[this.cursor].disabled) {
output.push(color.yellow(this.warn));
}
return output.join(" ");
}
render() {
if (this.closed)
return;
if (this.firstRender)
this.out.write(cursor.hide);
super.render();
let prompt = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(false), this.renderDoneOrInstructions()].join(" ");
if (this.showMinError) {
prompt += color.red(`You must select a minimum of ${this.minSelected} choices.`);
this.showMinError = false;
}
prompt += this.renderOptions(this.value);
this.out.write(this.clear + prompt);
this.clear = clear(prompt, this.out.columns);
}
}
module.exports = MultiselectPrompt;
});
// node_modules/prompts/dist/elements/autocomplete.js
var require_autocomplete = __commonJS((exports, module) => {
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _asyncToGenerator(fn) {
return function() {
var self = this, args = arguments;
return new Promise(function(resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
var color = require_kleur();
var Prompt = require_prompt();
var _require = require_src();
var erase = _require.erase;
var cursor = _require.cursor;
var _require2 = require_util();
var style = _require2.style;
var clear = _require2.clear;
var figures = _require2.figures;
var wrap = _require2.wrap;
var entriesToDisplay = _require2.entriesToDisplay;
var getVal = (arr, i) => arr[i] && (arr[i].value || arr[i].title || arr[i]);
var getTitle = (arr, i) => arr[i] && (arr[i].title || arr[i].value || arr[i]);
var getIndex = (arr, valOrTitle) => {
const index = arr.findIndex((el) => el.value === valOrTitle || el.title === valOrTitle);
return index > -1 ? index : undefined;
};
class AutocompletePrompt extends Prompt {
constructor(opts = {}) {
super(opts);
this.msg = opts.message;
this.suggest = opts.suggest;
this.choices = opts.choices;
this.initial = typeof opts.initial === "number" ? opts.initial : getIndex(opts.choices, opts.initial);
this.select = this.initial || opts.cursor || 0;
this.i18n = {
noMatches: opts.noMatches || "no matches found"
};
this.fallback = opts.fallback || this.initial;
this.clearFirst = opts.clearFirst || false;
this.suggestions = [];
this.input = "";
this.limit = opts.limit || 10;
this.cursor = 0;
this.transform = style.render(opts.style);
this.scale = this.transform.scale;
this.render = this.render.bind(this);
this.complete = this.complete.bind(this);
this.clear = clear("", this.out.columns);
this.complete(this.render);
this.render();
}
set fallback(fb) {
this._fb = Number.isSafeInteger(parseInt(fb)) ? parseInt(fb) : fb;
}
get fallback() {
let choice;
if (typeof this._fb === "number")
choice = this.choices[this._fb];
else if (typeof this._fb === "string")
choice = {
title: this._fb
};
return choice || this._fb || {
title: this.i18n.noMatches
};
}
moveSelect(i) {
this.select = i;
if (this.suggestions.length > 0)
this.value = getVal(this.suggestions, i);
else
this.value = this.fallback.value;
this.fire();
}
complete(cb) {
var _this = this;
return _asyncToGenerator(function* () {
const p = _this.completing = _this.suggest(_this.input, _this.choices);
const suggestions = yield p;
if (_this.completing !== p)
return;
_this.suggestions = suggestions.map((s, i, arr) => ({
title: getTitle(arr, i),
value: getVal(arr, i),
description: s.description
}));
_this.completing = false;
const l = Math.max(suggestions.length - 1, 0);
_this.moveSelect(Math.min(l, _this.select));
cb && cb();
})();
}
reset() {
this.input = "";
this.complete(() => {
this.moveSelect(this.initial !== undefined ? this.initial : 0);
this.render();
});
this.render();
}
exit() {
if (this.clearFirst && this.input.length > 0) {
this.reset();
} else {
this.done = this.exited = true;
this.aborted = false;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
}
abort() {
this.done = this.aborted = true;
this.exited = false;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
submit() {
this.done = true;
this.aborted = this.exited = false;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
_(c, key) {
let s1 = this.input.slice(0, this.cursor);
let s2 = this.input.slice(this.cursor);
this.input = `${s1}${c}${s2}`;
this.cursor = s1.length + 1;
this.complete(this.render);
this.render();
}
delete() {
if (this.cursor === 0)
return this.bell();
let s1 = this.input.slice(0, this.cursor - 1);
let s2 = this.input.slice(this.cursor);
this.input = `${s1}${s2}`;
this.complete(this.render);
this.cursor = this.cursor - 1;
this.render();
}
deleteForward() {
if (this.cursor * this.scale >= this.rendered.length)
return this.bell();
let s1 = this.input.slice(0, this.cursor);
let s2 = this.input.slice(this.cursor + 1);
this.input = `${s1}${s2}`;
this.complete(this.render);
this.render();
}
first() {
this.moveSelect(0);
this.render();
}
last() {
this.moveSelect(this.suggestions.length - 1);
this.render();
}
up() {
if (this.select === 0) {
this.moveSelect(this.suggestions.length - 1);
} else {
this.moveSelect(this.select - 1);
}
this.render();
}
down() {
if (this.select === this.suggestions.length - 1) {
this.moveSelect(0);
} else {
this.moveSelect(this.select + 1);
}
this.render();
}
next() {
if (this.select === this.suggestions.length - 1) {
this.moveSelect(0);
} else
this.moveSelect(this.select + 1);
this.render();
}
nextPage() {
this.moveSelect(Math.min(this.select + this.limit, this.suggestions.length - 1));
this.render();
}
prevPage() {
this.moveSelect(Math.max(this.select - this.limit, 0));
this.render();
}
left() {
if (this.cursor <= 0)
return this.bell();
this.cursor = this.cursor - 1;
this.render();
}
right() {
if (this.cursor * this.scale >= this.rendered.length)
return this.bell();
this.cursor = this.cursor + 1;
this.render();
}
renderOption(v, hovered, isStart, isEnd) {
let desc;
let prefix = isStart ? figures.arrowUp : isEnd ? figures.arrowDown : " ";
let title = hovered ? color.cyan().underline(v.title) : v.title;
prefix = (hovered ? color.cyan(figures.pointer) + " " : " ") + prefix;
if (v.description) {
desc = ` - ${v.description}`;
if (prefix.length + title.length + desc.length >= this.out.columns || v.description.split(/\r?\n/).length > 1) {
desc = `
` + wrap(v.description, {
margin: 3,
width: this.out.columns
});
}
}
return prefix + " " + title + color.gray(desc || "");
}
render() {
if (this.closed)
return;
if (this.firstRender)
this.out.write(cursor.hide);
else
this.out.write(clear(this.outputText, this.out.columns));
super.render();
let _entriesToDisplay = entriesToDisplay(this.select, this.choices.length, this.limit), startIndex = _entriesToDisplay.startIndex, endIndex = _entriesToDisplay.endIndex;
this.outputText = [style.symbol(this.done, this.aborted, this.exited), color.bold(this.msg), style.delimiter(this.completing), this.done && this.suggestions[this.select] ? this.suggestions[this.select].title : this.rendered = this.transform.render(this.input)].join(" ");
if (!this.done) {
const suggestions = this.suggestions.slice(startIndex, endIndex).map((item, i) => this.renderOption(item, this.select === i + startIndex, i === 0 && startIndex > 0, i + startIndex === endIndex - 1 && endIndex < this.choices.length)).join(`
`);
this.outputText += `
` + (suggestions || color.gray(this.fallback.title));
}
this.out.write(erase.line + cursor.to(0) + this.outputText);
}
}
module.exports = AutocompletePrompt;
});
// node_modules/prompts/dist/elements/autocompleteMultiselect.js
var require_autocompleteMultiselect = __commonJS((exports, module) => {
var color = require_kleur();
var _require = require_src();
var cursor = _require.cursor;
var MultiselectPrompt = require_multiselect();
var _require2 = require_util();
var clear = _require2.clear;
var style = _require2.style;
var figures = _require2.figures;
class AutocompleteMultiselectPrompt extends MultiselectPrompt {
constructor(opts = {}) {
opts.overrideRender = true;
super(opts);
this.inputValue = "";
this.clear = clear("", this.out.columns);
this.filteredOptions = this.value;
this.render();
}
last() {
this.cursor = this.filteredOptions.length - 1;
this.render();
}
next() {
this.cursor = (this.cursor + 1) % this.filteredOptions.length;
this.render();
}
up() {
if (this.cursor === 0) {
this.cursor = this.filteredOptions.length - 1;
} else {
this.cursor--;
}
this.render();
}
down() {
if (this.cursor === this.filteredOptions.length - 1) {
this.cursor = 0;
} else {
this.cursor++;
}
this.render();
}
left() {
this.filteredOptions[this.cursor].selected = false;
this.render();
}
right() {
if (this.value.filter((e) => e.selected).length >= this.maxChoices)
return this.bell();
this.filteredOptions[this.cursor].selected = true;
this.render();
}
delete() {
if (this.inputValue.length) {
this.inputValue = this.inputValue.substr(0, this.inputValue.length - 1);
this.updateFilteredOptions();
}
}
updateFilteredOptions() {
const currentHighlight = this.filteredOptions[this.cursor];
this.filteredOptions = this.value.filter((v) => {
if (this.inputValue) {
if (typeof v.title === "string") {
if (v.title.toLowerCase().includes(this.inputValue.toLowerCase())) {
return true;
}
}
if (typeof v.value === "string") {
if (v.value.toLowerCase().includes(this.inputValue.toLowerCase())) {
return true;
}
}
return false;
}
return true;
});
const newHighlightIndex = this.filteredOptions.findIndex((v) => v === currentHighlight);
this.cursor = newHighlightIndex < 0 ? 0 : newHighlightIndex;
this.render();
}
handleSpaceToggle() {
const v = this.filteredOptions[this.cursor];
if (v.selected) {
v.selected = false;
this.render();
} else if (v.disabled || this.value.filter((e) => e.selected).length >= this.maxChoices) {
return this.bell();
} else {
v.selected = true;
this.render();
}
}
handleInputChange(c) {
this.inputValue = this.inputValue + c;
this.updateFilteredOptions();
}
_(c, key) {
if (c === " ") {
this.handleSpaceToggle();
} else {
this.handleInputChange(c);
}
}
renderInstructions() {
if (this.instructions === undefined || this.instructions) {
if (typeof this.instructions === "string") {
return this.instructions;
}
return `
Instructions:
${figures.arrowUp}/${figures.arrowDown}: Highlight option
${figures.arrowLeft}/${figures.arrowRight}/[space]: Toggle selection
[a,b,c]/delete: Filter choices
enter/return: Complete answer
`;
}
return "";
}
renderCurrentInput() {
return `
Filtered results for: ${this.inputValue ? this.inputValue : color.gray("Enter something to filter")}
`;
}
renderOption(cursor2, v, i) {
let title;
if (v.disabled)
title = cursor2 === i ? color.gray().underline(v.title) : color.strikethrough().gray(v.title);
else
title = cursor2 === i ? color.cyan().underline(v.title) : v.title;
return (v.selected ? color.green(figures.radioOn) : figures.radioOff) + " " + title;
}
renderDoneOrInstructions() {
if (this.done) {
return this.value.filter((e) => e.selected).map((v) => v.title).join(", ");
}
const output = [color.gray(this.hint), this.renderInstructions(), this.renderCurrentInput()];
if (this.filteredOptions.length && this.filteredOptions[this.cursor].disabled) {
output.push(color.yellow(this.warn));
}
return output.join(" ");
}
render() {
if (this.closed)
return;
if (this.firstRender)
this.out.write(cursor.hide);
super.render();
let prompt = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(false), this.renderDoneOrInstructions()].join(" ");
if (this.showMinError) {
prompt += color.red(`You must select a minimum of ${this.minSelected} choices.`);
this.showMinError = false;
}
prompt += this.renderOptions(this.filteredOptions);
this.out.write(this.clear + prompt);
this.clear = clear(prompt, this.out.columns);
}
}
module.exports = AutocompleteMultiselectPrompt;
});
// node_modules/prompts/dist/elements/confirm.js
var require_confirm = __commonJS((exports, module) => {
var color = require_kleur();
var Prompt = require_prompt();
var _require = require_util();
var style = _require.style;
var clear = _require.clear;
var _require2 = require_src();
var erase = _require2.erase;
var cursor = _require2.cursor;
class ConfirmPrompt extends Prompt {
constructor(opts = {}) {
super(opts);
this.msg = opts.message;
this.value = opts.initial;
this.initialValue = !!opts.initial;
this.yesMsg = opts.yes || "yes";
this.yesOption = opts.yesOption || "(Y/n)";
this.noMsg = opts.no || "no";
this.noOption = opts.noOption || "(y/N)";
this.render();
}
reset() {
this.value = this.initialValue;
this.fire();
this.render();
}
exit() {
this.abort();
}
abort() {
this.done = this.aborted = true;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
submit() {
this.value = this.value || false;
this.done = true;
this.aborted = false;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
_(c, key) {
if (c.toLowerCase() === "y") {
this.value = true;
return this.submit();
}
if (c.toLowerCase() === "n") {
this.value = false;
return this.submit();
}
return this.bell();
}
render() {
if (this.closed)
return;
if (this.firstRender)
this.out.write(cursor.hide);
else
this.out.write(clear(this.outputText, this.out.columns));
super.render();
this.outputText = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(this.done), this.done ? this.value ? this.yesMsg : this.noMsg : color.gray(this.initialValue ? this.yesOption : this.noOption)].join(" ");
this.out.write(erase.line + cursor.to(0) + this.outputText);
}
}
module.exports = ConfirmPrompt;
});
// node_modules/prompts/dist/elements/index.js
var require_elements = __commonJS((exports, module) => {
module.exports = {
TextPrompt: require_text(),
SelectPrompt: require_select(),
TogglePrompt: require_toggle(),
DatePrompt: require_date(),
NumberPrompt: require_number(),
MultiselectPrompt: require_multiselect(),
AutocompletePrompt: require_autocomplete(),
AutocompleteMultiselectPrompt: require_autocompleteMultiselect(),
ConfirmPrompt: require_confirm()
};
});
// node_modules/prompts/dist/prompts.js
var require_prompts = __commonJS((exports) => {
var $ = exports;
var el = require_elements();
var noop = (v) => v;
function toPrompt(type, args, opts = {}) {
return new Promise((res, rej) => {
const p = new el[type](args);
const onAbort = opts.onAbort || noop;
const onSubmit = opts.onSubmit || noop;
const onExit = opts.onExit || noop;
p.on("state", args.onState || noop);
p.on("submit", (x) => res(onSubmit(x)));
p.on("exit", (x) => res(onExit(x)));
p.on("abort", (x) => rej(onAbort(x)));
});
}
$.text = (args) => toPrompt("TextPrompt", args);
$.password = (args) => {
args.style = "password";
return $.text(args);
};
$.invisible = (args) => {
args.style = "invisible";
return $.text(args);
};
$.number = (args) => toPrompt("NumberPrompt", args);
$.date = (args) => toPrompt("DatePrompt", args);
$.confirm = (args) => toPrompt("ConfirmPrompt", args);
$.list = (args) => {
const sep = args.separator || ",";
return toPrompt("TextPrompt", args, {
onSubmit: (str) => str.split(sep).map((s) => s.trim())
});
};
$.toggle = (args) => toPrompt("TogglePrompt", args);
$.select = (args) => toPrompt("SelectPrompt", args);
$.multiselect = (args) => {
args.choices = [].concat(args.choices || []);
const toSelected = (items) => items.filter((item) => item.selected).map((item) => item.value);
return toPrompt("MultiselectPrompt", args, {
onAbort: toSelected,
onSubmit: toSelected
});
};
$.autocompleteMultiselect = (args) => {
args.choices = [].concat(args.choices || []);
const toSelected = (items) => items.filter((item) => item.selected).map((item) => item.value);
return toPrompt("AutocompleteMultiselectPrompt", args, {
onAbort: toSelected,
onSubmit: toSelected
});
};
var byTitle = (input, choices) => Promise.resolve(choices.filter((item) => item.title.slice(0, input.length).toLowerCase() === input.toLowerCase()));
$.autocomplete = (args) => {
args.suggest = args.suggest || byTitle;
args.choices = [].concat(args.choices || []);
return toPrompt("AutocompletePrompt", args);
};
});
// node_modules/prompts/dist/index.js
var require_dist = __commonJS((exports, module) => {
function ownKeys(object, enumerableOnly) {
var keys = Object.keys(object);
if (Object.getOwnPropertySymbols) {
var symbols = Object.getOwnPropertySymbols(object);
if (enumerableOnly) {
symbols = symbols.filter(function(sym) {
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
});
}
keys.push.apply(keys, symbols);
}
return keys;
}
function _objectSpread(target) {
for (var i = 1;i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
if (i % 2) {
ownKeys(Object(source), true).forEach(function(key) {
_defineProperty(target, key, source[key]);
});
} else if (Object.getOwnPropertyDescriptors) {
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
} else {
ownKeys(Object(source)).forEach(function(key) {
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
});
}
}
return target;
}
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, { value, enumerable: true, configurable: true, writable: true });
} else {
obj[key] = value;
}
return obj;
}
function _createForOfIteratorHelper(o, allowArrayLike) {
var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
if (!it) {
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
if (it)
o = it;
var i = 0;
var F = function F() {};
return { s: F, n: function n() {
if (i >= o.length)
return { done: true };
return { done: false, value: o[i++] };
}, e: function e(_e) {
throw _e;
}, f: F };
}
throw new TypeError(`Invalid attempt to iterate non-iterable instance.
In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`);
}
var normalCompletion = true, didErr = false, err;
return { s: function s() {
it = it.call(o);
}, n: function n() {
var step = it.next();
normalCompletion = step.done;
return step;
}, e: function e(_e2) {
didErr = true;
err = _e2;
}, f: function f() {
try {
if (!normalCompletion && it.return != null)
it.return();
} finally {
if (didErr)
throw err;
}
} };
}
function _unsupportedIterableToArray(o, minLen) {
if (!o)
return;
if (typeof o === "string")
return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor)
n = o.constructor.name;
if (n === "Map" || n === "Set")
return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))
return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length)
len = arr.length;
for (var i = 0, arr2 = new Array(len);i < len; i++)
arr2[i] = arr[i];
return arr2;
}
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _asyncToGenerator(fn) {
return function() {
var self = this, args = arguments;
return new Promise(function(resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
var prompts = require_prompts();
var passOn = ["suggest", "format", "onState", "validate", "onRender", "type"];
var noop = () => {};
function prompt() {
return _prompt.apply(this, arguments);
}
function _prompt() {
_prompt = _asyncToGenerator(function* (questions = [], {
onSubmit = noop,
onCancel = noop
} = {}) {
const answers = {};
const override2 = prompt._override || {};
questions = [].concat(questions);
let answer, question, quit, name, type, lastPrompt;
const getFormattedAnswer = /* @__PURE__ */ function() {
var _ref = _asyncToGenerator(function* (question2, answer2, skipValidation = false) {
if (!skipValidation && question2.validate && question2.validate(answer2) !== true) {
return;
}
return question2.format ? yield question2.format(answer2, answers) : answer2;
});
return function getFormattedAnswer(_x, _x2) {
return _ref.apply(this, arguments);
};
}();
var _iterator = _createForOfIteratorHelper(questions), _step;
try {
for (_iterator.s();!(_step = _iterator.n()).done; ) {
question = _step.value;
var _question = question;
name = _question.name;
type = _question.type;
if (typeof type === "function") {
type = yield type(answer, _objectSpread({}, answers), question);
question["type"] = type;
}
if (!type)
continue;
for (let key in question) {
if (passOn.includes(key))
continue;
let value = question[key];
question[key] = typeof value === "function" ? yield value(answer, _objectSpread({}, answers), lastPrompt) : value;
}
lastPrompt = question;
if (typeof question.message !== "string") {
throw new Error("prompt message is required");
}
var _question2 = question;
name = _question2.name;
type = _question2.type;
if (prompts[type] === undefined) {
throw new Error(`prompt type (${type}) is not defined`);
}
if (override2[question.name] !== undefined) {
answer = yield getFormattedAnswer(question, override2[question.name]);
if (answer !== undefined) {
answers[name] = answer;
continue;
}
}
try {
answer = prompt._injected ? getInjectedAnswer(prompt._injected, question.initial) : yield prompts[type](question);
answers[name] = answer = yield getFormattedAnswer(question, answer, true);
quit = yield onSubmit(question, answer, answers);
} catch (err) {
quit = !(yield onCancel(question, answers));
}
if (quit)
return answers;
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
return answers;
});
return _prompt.apply(this, arguments);
}
function getInjectedAnswer(injected, deafultValue) {
const answer = injected.shift();
if (answer instanceof Error) {
throw answer;
}
return answer === undefined ? deafultValue : answer;
}
function inject(answers) {
prompt._injected = (prompt._injected || []).concat(answers);
}
function override(answers) {
prompt._override = Object.assign({}, answers);
}
module.exports = Object.assign(prompt, {
prompt,
prompts,
inject,
override
});
});
// node_modules/prompts/lib/util/action.js
var require_action2 = __commonJS((exports, module) => {
module.exports = (key, isSelect) => {
if (key.meta && key.name !== "escape")
return;
if (key.ctrl) {
if (key.name === "a")
return "first";
if (key.name === "c")
return "abort";
if (key.name === "d")
return "abort";
if (key.name === "e")
return "last";
if (key.name === "g")
return "reset";
}
if (isSelect) {
if (key.name === "j")
return "down";
if (key.name === "k")
return "up";
}
if (key.name === "return")
return "submit";
if (key.name === "enter")
return "submit";
if (key.name === "backspace")
return "delete";
if (key.name === "delete")
return "deleteForward";
if (key.name === "abort")
return "abort";
if (key.name === "escape")
return "exit";
if (key.name === "tab")
return "next";
if (key.name === "pagedown")
return "nextPage";
if (key.name === "pageup")
return "prevPage";
if (key.name === "home")
return "home";
if (key.name === "end")
return "end";
if (key.name === "up")
return "up";
if (key.name === "down")
return "down";
if (key.name === "right")
return "right";
if (key.name === "left")
return "left";
return false;
};
});
// node_modules/prompts/lib/util/strip.js
var require_strip2 = __commonJS((exports, module) => {
module.exports = (str) => {
const pattern = [
"[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
"(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))"
].join("|");
const RGX = new RegExp(pattern, "g");
return typeof str === "string" ? str.replace(RGX, "") : str;
};
});
// node_modules/prompts/lib/util/clear.js
var require_clear2 = __commonJS((exports, module) => {
var strip = require_strip2();
var { erase, cursor } = require_src();
var width = (str) => [...strip(str)].length;
module.exports = function(prompt, perLine) {
if (!perLine)
return erase.line + cursor.to(0);
let rows = 0;
const lines = prompt.split(/\r?\n/);
for (let line of lines) {
rows += 1 + Math.floor(Math.max(width(line) - 1, 0) / perLine);
}
return erase.lines(rows);
};
});
// node_modules/prompts/lib/util/figures.js
var require_figures2 = __commonJS((exports, module) => {
var main = {
arrowUp: "\u2191",
arrowDown: "\u2193",
arrowLeft: "\u2190",
arrowRight: "\u2192",
radioOn: "\u25C9",
radioOff: "\u25EF",
tick: "\u2714",
cross: "\u2716",
ellipsis: "\u2026",
pointerSmall: "\u203A",
line: "\u2500",
pointer: "\u276F"
};
var win = {
arrowUp: main.arrowUp,
arrowDown: main.arrowDown,
arrowLeft: main.arrowLeft,
arrowRight: main.arrowRight,
radioOn: "(*)",
radioOff: "( )",
tick: "\u221A",
cross: "\xD7",
ellipsis: "...",
pointerSmall: "\xBB",
line: "\u2500",
pointer: ">"
};
var figures = process.platform === "win32" ? win : main;
module.exports = figures;
});
// node_modules/prompts/lib/util/style.js
var require_style2 = __commonJS((exports, module) => {
var c = require_kleur();
var figures = require_figures2();
var styles3 = Object.freeze({
password: { scale: 1, render: (input) => "*".repeat(input.length) },
emoji: { scale: 2, render: (input) => "\uD83D\uDE03".repeat(input.length) },
invisible: { scale: 0, render: (input) => "" },
default: { scale: 1, render: (input) => `${input}` }
});
var render = (type) => styles3[type] || styles3.default;
var symbols = Object.freeze({
aborted: c.red(figures.cross),
done: c.green(figures.tick),
exited: c.yellow(figures.cross),
default: c.cyan("?")
});
var symbol = (done, aborted, exited) => aborted ? symbols.aborted : exited ? symbols.exited : done ? symbols.done : symbols.default;
var delimiter = (completing) => c.gray(completing ? figures.ellipsis : figures.pointerSmall);
var item = (expandable, expanded) => c.gray(expandable ? expanded ? figures.pointerSmall : "+" : figures.line);
module.exports = {
styles: styles3,
render,
symbols,
symbol,
delimiter,
item
};
});
// node_modules/prompts/lib/util/lines.js
var require_lines2 = __commonJS((exports, module) => {
var strip = require_strip2();
module.exports = function(msg, perLine) {
let lines = String(strip(msg) || "").split(/\r?\n/);
if (!perLine)
return lines.length;
return lines.map((l) => Math.ceil(l.length / perLine)).reduce((a, b) => a + b);
};
});
// node_modules/prompts/lib/util/wrap.js
var require_wrap2 = __commonJS((exports, module) => {
module.exports = (msg, opts = {}) => {
const tab = Number.isSafeInteger(parseInt(opts.margin)) ? new Array(parseInt(opts.margin)).fill(" ").join("") : opts.margin || "";
const width = opts.width;
return (msg || "").split(/\r?\n/g).map((line) => line.split(/\s+/g).reduce((arr, w) => {
if (w.length + tab.length >= width || arr[arr.length - 1].length + w.length + 1 < width)
arr[arr.length - 1] += ` ${w}`;
else
arr.push(`${tab}${w}`);
return arr;
}, [tab]).join(`
`)).join(`
`);
};
});
// node_modules/prompts/lib/util/entriesToDisplay.js
var require_entriesToDisplay2 = __commonJS((exports, module) => {
module.exports = (cursor, total, maxVisible) => {
maxVisible = maxVisible || total;
let startIndex = Math.min(total - maxVisible, cursor - Math.floor(maxVisible / 2));
if (startIndex < 0)
startIndex = 0;
let endIndex = Math.min(startIndex + maxVisible, total);
return { startIndex, endIndex };
};
});
// node_modules/prompts/lib/util/index.js
var require_util2 = __commonJS((exports, module) => {
module.exports = {
action: require_action2(),
clear: require_clear2(),
style: require_style2(),
strip: require_strip2(),
figures: require_figures2(),
lines: require_lines2(),
wrap: require_wrap2(),
entriesToDisplay: require_entriesToDisplay2()
};
});
// node_modules/prompts/lib/elements/prompt.js
var require_prompt2 = __commonJS((exports, module) => {
var readline = __require("readline");
var { action } = require_util2();
var EventEmitter = __require("events");
var { beep, cursor } = require_src();
var color = require_kleur();
class Prompt extends EventEmitter {
constructor(opts = {}) {
super();
this.firstRender = true;
this.in = opts.stdin || process.stdin;
this.out = opts.stdout || process.stdout;
this.onRender = (opts.onRender || (() => {
return;
})).bind(this);
const rl = readline.createInterface({ input: this.in, escapeCodeTimeout: 50 });
readline.emitKeypressEvents(this.in, rl);
if (this.in.isTTY)
this.in.setRawMode(true);
const isSelect = ["SelectPrompt", "MultiselectPrompt"].indexOf(this.constructor.name) > -1;
const keypress = (str, key) => {
let a = action(key, isSelect);
if (a === false) {
this._ && this._(str, key);
} else if (typeof this[a] === "function") {
this[a](key);
} else {
this.bell();
}
};
this.close = () => {
this.out.write(cursor.show);
this.in.removeListener("keypress", keypress);
if (this.in.isTTY)
this.in.setRawMode(false);
rl.close();
this.emit(this.aborted ? "abort" : this.exited ? "exit" : "submit", this.value);
this.closed = true;
};
this.in.on("keypress", keypress);
}
fire() {
this.emit("state", {
value: this.value,
aborted: !!this.aborted,
exited: !!this.exited
});
}
bell() {
this.out.write(beep);
}
render() {
this.onRender(color);
if (this.firstRender)
this.firstRender = false;
}
}
module.exports = Prompt;
});
// node_modules/prompts/lib/elements/text.js
var require_text2 = __commonJS((exports, module) => {
var color = require_kleur();
var Prompt = require_prompt2();
var { erase, cursor } = require_src();
var { style, clear, lines, figures } = require_util2();
class TextPrompt extends Prompt {
constructor(opts = {}) {
super(opts);
this.transform = style.render(opts.style);
this.scale = this.transform.scale;
this.msg = opts.message;
this.initial = opts.initial || ``;
this.validator = opts.validate || (() => true);
this.value = ``;
this.errorMsg = opts.error || `Please Enter A Valid Value`;
this.cursor = Number(!!this.initial);
this.cursorOffset = 0;
this.clear = clear(``, this.out.columns);
this.render();
}
set value(v) {
if (!v && this.initial) {
this.placeholder = true;
this.rendered = color.gray(this.transform.render(this.initial));
} else {
this.placeholder = false;
this.rendered = this.transform.render(v);
}
this._value = v;
this.fire();
}
get value() {
return this._value;
}
reset() {
this.value = ``;
this.cursor = Number(!!this.initial);
this.cursorOffset = 0;
this.fire();
this.render();
}
exit() {
this.abort();
}
abort() {
this.value = this.value || this.initial;
this.done = this.aborted = true;
this.error = false;
this.red = false;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
async validate() {
let valid = await this.validator(this.value);
if (typeof valid === `string`) {
this.errorMsg = valid;
valid = false;
}
this.error = !valid;
}
async submit() {
this.value = this.value || this.initial;
this.cursorOffset = 0;
this.cursor = this.rendered.length;
await this.validate();
if (this.error) {
this.red = true;
this.fire();
this.render();
return;
}
this.done = true;
this.aborted = false;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
next() {
if (!this.placeholder)
return this.bell();
this.value = this.initial;
this.cursor = this.rendered.length;
this.fire();
this.render();
}
moveCursor(n) {
if (this.placeholder)
return;
this.cursor = this.cursor + n;
this.cursorOffset += n;
}
_(c, key) {
let s1 = this.value.slice(0, this.cursor);
let s2 = this.value.slice(this.cursor);
this.value = `${s1}${c}${s2}`;
this.red = false;
this.cursor = this.placeholder ? 0 : s1.length + 1;
this.render();
}
delete() {
if (this.isCursorAtStart())
return this.bell();
let s1 = this.value.slice(0, this.cursor - 1);
let s2 = this.value.slice(this.cursor);
this.value = `${s1}${s2}`;
this.red = false;
if (this.isCursorAtStart()) {
this.cursorOffset = 0;
} else {
this.cursorOffset++;
this.moveCursor(-1);
}
this.render();
}
deleteForward() {
if (this.cursor * this.scale >= this.rendered.length || this.placeholder)
return this.bell();
let s1 = this.value.slice(0, this.cursor);
let s2 = this.value.slice(this.cursor + 1);
this.value = `${s1}${s2}`;
this.red = false;
if (this.isCursorAtEnd()) {
this.cursorOffset = 0;
} else {
this.cursorOffset++;
}
this.render();
}
first() {
this.cursor = 0;
this.render();
}
last() {
this.cursor = this.value.length;
this.render();
}
left() {
if (this.cursor <= 0 || this.placeholder)
return this.bell();
this.moveCursor(-1);
this.render();
}
right() {
if (this.cursor * this.scale >= this.rendered.length || this.placeholder)
return this.bell();
this.moveCursor(1);
this.render();
}
isCursorAtStart() {
return this.cursor === 0 || this.placeholder && this.cursor === 1;
}
isCursorAtEnd() {
return this.cursor === this.rendered.length || this.placeholder && this.cursor === this.rendered.length + 1;
}
render() {
if (this.closed)
return;
if (!this.firstRender) {
if (this.outputError)
this.out.write(cursor.down(lines(this.outputError, this.out.columns) - 1) + clear(this.outputError, this.out.columns));
this.out.write(clear(this.outputText, this.out.columns));
}
super.render();
this.outputError = "";
this.outputText = [
style.symbol(this.done, this.aborted),
color.bold(this.msg),
style.delimiter(this.done),
this.red ? color.red(this.rendered) : this.rendered
].join(` `);
if (this.error) {
this.outputError += this.errorMsg.split(`
`).reduce((a, l, i) => a + `
${i ? " " : figures.pointerSmall} ${color.red().italic(l)}`, ``);
}
this.out.write(erase.line + cursor.to(0) + this.outputText + cursor.save + this.outputError + cursor.restore + cursor.move(this.cursorOffset, 0));
}
}
module.exports = TextPrompt;
});
// node_modules/prompts/lib/elements/select.js
var require_select2 = __commonJS((exports, module) => {
var color = require_kleur();
var Prompt = require_prompt2();
var { style, clear, figures, wrap, entriesToDisplay } = require_util2();
var { cursor } = require_src();
class SelectPrompt extends Prompt {
constructor(opts = {}) {
super(opts);
this.msg = opts.message;
this.hint = opts.hint || "- Use arrow-keys. Return to submit.";
this.warn = opts.warn || "- This option is disabled";
this.cursor = opts.initial || 0;
this.choices = opts.choices.map((ch, idx) => {
if (typeof ch === "string")
ch = { title: ch, value: idx };
return {
title: ch && (ch.title || ch.value || ch),
value: ch && (ch.value === undefined ? idx : ch.value),
description: ch && ch.description,
selected: ch && ch.selected,
disabled: ch && ch.disabled
};
});
this.optionsPerPage = opts.optionsPerPage || 10;
this.value = (this.choices[this.cursor] || {}).value;
this.clear = clear("", this.out.columns);
this.render();
}
moveCursor(n) {
this.cursor = n;
this.value = this.choices[n].value;
this.fire();
}
reset() {
this.moveCursor(0);
this.fire();
this.render();
}
exit() {
this.abort();
}
abort() {
this.done = this.aborted = true;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
submit() {
if (!this.selection.disabled) {
this.done = true;
this.aborted = false;
this.fire();
this.render();
this.out.write(`
`);
this.close();
} else
this.bell();
}
first() {
this.moveCursor(0);
this.render();
}
last() {
this.moveCursor(this.choices.length - 1);
this.render();
}
up() {
if (this.cursor === 0) {
this.moveCursor(this.choices.length - 1);
} else {
this.moveCursor(this.cursor - 1);
}
this.render();
}
down() {
if (this.cursor === this.choices.length - 1) {
this.moveCursor(0);
} else {
this.moveCursor(this.cursor + 1);
}
this.render();
}
next() {
this.moveCursor((this.cursor + 1) % this.choices.length);
this.render();
}
_(c, key) {
if (c === " ")
return this.submit();
}
get selection() {
return this.choices[this.cursor];
}
render() {
if (this.closed)
return;
if (this.firstRender)
this.out.write(cursor.hide);
else
this.out.write(clear(this.outputText, this.out.columns));
super.render();
let { startIndex, endIndex } = entriesToDisplay(this.cursor, this.choices.length, this.optionsPerPage);
this.outputText = [
style.symbol(this.done, this.aborted),
color.bold(this.msg),
style.delimiter(false),
this.done ? this.selection.title : this.selection.disabled ? color.yellow(this.warn) : color.gray(this.hint)
].join(" ");
if (!this.done) {
this.outputText += `
`;
for (let i = startIndex;i < endIndex; i++) {
let title, prefix, desc = "", v = this.choices[i];
if (i === startIndex && startIndex > 0) {
prefix = figures.arrowUp;
} else if (i === endIndex - 1 && endIndex < this.choices.length) {
prefix = figures.arrowDown;
} else {
prefix = " ";
}
if (v.disabled) {
title = this.cursor === i ? color.gray().underline(v.title) : color.strikethrough().gray(v.title);
prefix = (this.cursor === i ? color.bold().gray(figures.pointer) + " " : " ") + prefix;
} else {
title = this.cursor === i ? color.cyan().underline(v.title) : v.title;
prefix = (this.cursor === i ? color.cyan(figures.pointer) + " " : " ") + prefix;
if (v.description && this.cursor === i) {
desc = ` - ${v.description}`;
if (prefix.length + title.length + desc.length >= this.out.columns || v.description.split(/\r?\n/).length > 1) {
desc = `
` + wrap(v.description, { margin: 3, width: this.out.columns });
}
}
}
this.outputText += `${prefix} ${title}${color.gray(desc)}
`;
}
}
this.out.write(this.outputText);
}
}
module.exports = SelectPrompt;
});
// node_modules/prompts/lib/elements/toggle.js
var require_toggle2 = __commonJS((exports, module) => {
var color = require_kleur();
var Prompt = require_prompt2();
var { style, clear } = require_util2();
var { cursor, erase } = require_src();
class TogglePrompt extends Prompt {
constructor(opts = {}) {
super(opts);
this.msg = opts.message;
this.value = !!opts.initial;
this.active = opts.active || "on";
this.inactive = opts.inactive || "off";
this.initialValue = this.value;
this.render();
}
reset() {
this.value = this.initialValue;
this.fire();
this.render();
}
exit() {
this.abort();
}
abort() {
this.done = this.aborted = true;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
submit() {
this.done = true;
this.aborted = false;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
deactivate() {
if (this.value === false)
return this.bell();
this.value = false;
this.render();
}
activate() {
if (this.value === true)
return this.bell();
this.value = true;
this.render();
}
delete() {
this.deactivate();
}
left() {
this.deactivate();
}
right() {
this.activate();
}
down() {
this.deactivate();
}
up() {
this.activate();
}
next() {
this.value = !this.value;
this.fire();
this.render();
}
_(c, key) {
if (c === " ") {
this.value = !this.value;
} else if (c === "1") {
this.value = true;
} else if (c === "0") {
this.value = false;
} else
return this.bell();
this.render();
}
render() {
if (this.closed)
return;
if (this.firstRender)
this.out.write(cursor.hide);
else
this.out.write(clear(this.outputText, this.out.columns));
super.render();
this.outputText = [
style.symbol(this.done, this.aborted),
color.bold(this.msg),
style.delimiter(this.done),
this.value ? this.inactive : color.cyan().underline(this.inactive),
color.gray("/"),
this.value ? color.cyan().underline(this.active) : this.active
].join(" ");
this.out.write(erase.line + cursor.to(0) + this.outputText);
}
}
module.exports = TogglePrompt;
});
// node_modules/prompts/lib/dateparts/datepart.js
var require_datepart2 = __commonJS((exports, module) => {
class DatePart {
constructor({ token, date, parts, locales }) {
this.token = token;
this.date = date || new Date;
this.parts = parts || [this];
this.locales = locales || {};
}
up() {}
down() {}
next() {
const currentIdx = this.parts.indexOf(this);
return this.parts.find((part, idx) => idx > currentIdx && part instanceof DatePart);
}
setTo(val) {}
prev() {
let parts = [].concat(this.parts).reverse();
const currentIdx = parts.indexOf(this);
return parts.find((part, idx) => idx > currentIdx && part instanceof DatePart);
}
toString() {
return String(this.date);
}
}
module.exports = DatePart;
});
// node_modules/prompts/lib/dateparts/meridiem.js
var require_meridiem2 = __commonJS((exports, module) => {
var DatePart = require_datepart2();
class Meridiem extends DatePart {
constructor(opts = {}) {
super(opts);
}
up() {
this.date.setHours((this.date.getHours() + 12) % 24);
}
down() {
this.up();
}
toString() {
let meridiem = this.date.getHours() > 12 ? "pm" : "am";
return /\A/.test(this.token) ? meridiem.toUpperCase() : meridiem;
}
}
module.exports = Meridiem;
});
// node_modules/prompts/lib/dateparts/day.js
var require_day2 = __commonJS((exports, module) => {
var DatePart = require_datepart2();
var pos = (n) => {
n = n % 10;
return n === 1 ? "st" : n === 2 ? "nd" : n === 3 ? "rd" : "th";
};
class Day extends DatePart {
constructor(opts = {}) {
super(opts);
}
up() {
this.date.setDate(this.date.getDate() + 1);
}
down() {
this.date.setDate(this.date.getDate() - 1);
}
setTo(val) {
this.date.setDate(parseInt(val.substr(-2)));
}
toString() {
let date = this.date.getDate();
let day = this.date.getDay();
return this.token === "DD" ? String(date).padStart(2, "0") : this.token === "Do" ? date + pos(date) : this.token === "d" ? day + 1 : this.token === "ddd" ? this.locales.weekdaysShort[day] : this.token === "dddd" ? this.locales.weekdays[day] : date;
}
}
module.exports = Day;
});
// node_modules/prompts/lib/dateparts/hours.js
var require_hours2 = __commonJS((exports, module) => {
var DatePart = require_datepart2();
class Hours extends DatePart {
constructor(opts = {}) {
super(opts);
}
up() {
this.date.setHours(this.date.getHours() + 1);
}
down() {
this.date.setHours(this.date.getHours() - 1);
}
setTo(val) {
this.date.setHours(parseInt(val.substr(-2)));
}
toString() {
let hours = this.date.getHours();
if (/h/.test(this.token))
hours = hours % 12 || 12;
return this.token.length > 1 ? String(hours).padStart(2, "0") : hours;
}
}
module.exports = Hours;
});
// node_modules/prompts/lib/dateparts/milliseconds.js
var require_milliseconds2 = __commonJS((exports, module) => {
var DatePart = require_datepart2();
class Milliseconds extends DatePart {
constructor(opts = {}) {
super(opts);
}
up() {
this.date.setMilliseconds(this.date.getMilliseconds() + 1);
}
down() {
this.date.setMilliseconds(this.date.getMilliseconds() - 1);
}
setTo(val) {
this.date.setMilliseconds(parseInt(val.substr(-this.token.length)));
}
toString() {
return String(this.date.getMilliseconds()).padStart(4, "0").substr(0, this.token.length);
}
}
module.exports = Milliseconds;
});
// node_modules/prompts/lib/dateparts/minutes.js
var require_minutes2 = __commonJS((exports, module) => {
var DatePart = require_datepart2();
class Minutes extends DatePart {
constructor(opts = {}) {
super(opts);
}
up() {
this.date.setMinutes(this.date.getMinutes() + 1);
}
down() {
this.date.setMinutes(this.date.getMinutes() - 1);
}
setTo(val) {
this.date.setMinutes(parseInt(val.substr(-2)));
}
toString() {
let m = this.date.getMinutes();
return this.token.length > 1 ? String(m).padStart(2, "0") : m;
}
}
module.exports = Minutes;
});
// node_modules/prompts/lib/dateparts/month.js
var require_month2 = __commonJS((exports, module) => {
var DatePart = require_datepart2();
class Month extends DatePart {
constructor(opts = {}) {
super(opts);
}
up() {
this.date.setMonth(this.date.getMonth() + 1);
}
down() {
this.date.setMonth(this.date.getMonth() - 1);
}
setTo(val) {
val = parseInt(val.substr(-2)) - 1;
this.date.setMonth(val < 0 ? 0 : val);
}
toString() {
let month = this.date.getMonth();
let tl = this.token.length;
return tl === 2 ? String(month + 1).padStart(2, "0") : tl === 3 ? this.locales.monthsShort[month] : tl === 4 ? this.locales.months[month] : String(month + 1);
}
}
module.exports = Month;
});
// node_modules/prompts/lib/dateparts/seconds.js
var require_seconds2 = __commonJS((exports, module) => {
var DatePart = require_datepart2();
class Seconds extends DatePart {
constructor(opts = {}) {
super(opts);
}
up() {
this.date.setSeconds(this.date.getSeconds() + 1);
}
down() {
this.date.setSeconds(this.date.getSeconds() - 1);
}
setTo(val) {
this.date.setSeconds(parseInt(val.substr(-2)));
}
toString() {
let s = this.date.getSeconds();
return this.token.length > 1 ? String(s).padStart(2, "0") : s;
}
}
module.exports = Seconds;
});
// node_modules/prompts/lib/dateparts/year.js
var require_year2 = __commonJS((exports, module) => {
var DatePart = require_datepart2();
class Year extends DatePart {
constructor(opts = {}) {
super(opts);
}
up() {
this.date.setFullYear(this.date.getFullYear() + 1);
}
down() {
this.date.setFullYear(this.date.getFullYear() - 1);
}
setTo(val) {
this.date.setFullYear(val.substr(-4));
}
toString() {
let year = String(this.date.getFullYear()).padStart(4, "0");
return this.token.length === 2 ? year.substr(-2) : year;
}
}
module.exports = Year;
});
// node_modules/prompts/lib/dateparts/index.js
var require_dateparts2 = __commonJS((exports, module) => {
module.exports = {
DatePart: require_datepart2(),
Meridiem: require_meridiem2(),
Day: require_day2(),
Hours: require_hours2(),
Milliseconds: require_milliseconds2(),
Minutes: require_minutes2(),
Month: require_month2(),
Seconds: require_seconds2(),
Year: require_year2()
};
});
// node_modules/prompts/lib/elements/date.js
var require_date2 = __commonJS((exports, module) => {
var color = require_kleur();
var Prompt = require_prompt2();
var { style, clear, figures } = require_util2();
var { erase, cursor } = require_src();
var { DatePart, Meridiem, Day, Hours, Milliseconds, Minutes, Month, Seconds, Year } = require_dateparts2();
var regex = /\\(.)|"((?:\\["\\]|[^"])+)"|(D[Do]?|d{3,4}|d)|(M{1,4})|(YY(?:YY)?)|([aA])|([Hh]{1,2})|(m{1,2})|(s{1,2})|(S{1,4})|./g;
var regexGroups = {
1: ({ token }) => token.replace(/\\(.)/g, "$1"),
2: (opts) => new Day(opts),
3: (opts) => new Month(opts),
4: (opts) => new Year(opts),
5: (opts) => new Meridiem(opts),
6: (opts) => new Hours(opts),
7: (opts) => new Minutes(opts),
8: (opts) => new Seconds(opts),
9: (opts) => new Milliseconds(opts)
};
var dfltLocales = {
months: "January,February,March,April,May,June,July,August,September,October,November,December".split(","),
monthsShort: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec".split(","),
weekdays: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday".split(","),
weekdaysShort: "Sun,Mon,Tue,Wed,Thu,Fri,Sat".split(",")
};
class DatePrompt extends Prompt {
constructor(opts = {}) {
super(opts);
this.msg = opts.message;
this.cursor = 0;
this.typed = "";
this.locales = Object.assign(dfltLocales, opts.locales);
this._date = opts.initial || new Date;
this.errorMsg = opts.error || "Please Enter A Valid Value";
this.validator = opts.validate || (() => true);
this.mask = opts.mask || "YYYY-MM-DD HH:mm:ss";
this.clear = clear("", this.out.columns);
this.render();
}
get value() {
return this.date;
}
get date() {
return this._date;
}
set date(date) {
if (date)
this._date.setTime(date.getTime());
}
set mask(mask) {
let result;
this.parts = [];
while (result = regex.exec(mask)) {
let match = result.shift();
let idx = result.findIndex((gr) => gr != null);
this.parts.push(idx in regexGroups ? regexGroups[idx]({ token: result[idx] || match, date: this.date, parts: this.parts, locales: this.locales }) : result[idx] || match);
}
let parts = this.parts.reduce((arr, i) => {
if (typeof i === "string" && typeof arr[arr.length - 1] === "string")
arr[arr.length - 1] += i;
else
arr.push(i);
return arr;
}, []);
this.parts.splice(0);
this.parts.push(...parts);
this.reset();
}
moveCursor(n) {
this.typed = "";
this.cursor = n;
this.fire();
}
reset() {
this.moveCursor(this.parts.findIndex((p) => p instanceof DatePart));
this.fire();
this.render();
}
exit() {
this.abort();
}
abort() {
this.done = this.aborted = true;
this.error = false;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
async validate() {
let valid = await this.validator(this.value);
if (typeof valid === "string") {
this.errorMsg = valid;
valid = false;
}
this.error = !valid;
}
async submit() {
await this.validate();
if (this.error) {
this.color = "red";
this.fire();
this.render();
return;
}
this.done = true;
this.aborted = false;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
up() {
this.typed = "";
this.parts[this.cursor].up();
this.render();
}
down() {
this.typed = "";
this.parts[this.cursor].down();
this.render();
}
left() {
let prev = this.parts[this.cursor].prev();
if (prev == null)
return this.bell();
this.moveCursor(this.parts.indexOf(prev));
this.render();
}
right() {
let next = this.parts[this.cursor].next();
if (next == null)
return this.bell();
this.moveCursor(this.parts.indexOf(next));
this.render();
}
next() {
let next = this.parts[this.cursor].next();
this.moveCursor(next ? this.parts.indexOf(next) : this.parts.findIndex((part) => part instanceof DatePart));
this.render();
}
_(c) {
if (/\d/.test(c)) {
this.typed += c;
this.parts[this.cursor].setTo(this.typed);
this.render();
}
}
render() {
if (this.closed)
return;
if (this.firstRender)
this.out.write(cursor.hide);
else
this.out.write(clear(this.outputText, this.out.columns));
super.render();
this.outputText = [
style.symbol(this.done, this.aborted),
color.bold(this.msg),
style.delimiter(false),
this.parts.reduce((arr, p, idx) => arr.concat(idx === this.cursor && !this.done ? color.cyan().underline(p.toString()) : p), []).join("")
].join(" ");
if (this.error) {
this.outputText += this.errorMsg.split(`
`).reduce((a, l, i) => a + `
${i ? ` ` : figures.pointerSmall} ${color.red().italic(l)}`, ``);
}
this.out.write(erase.line + cursor.to(0) + this.outputText);
}
}
module.exports = DatePrompt;
});
// node_modules/prompts/lib/elements/number.js
var require_number2 = __commonJS((exports, module) => {
var color = require_kleur();
var Prompt = require_prompt2();
var { cursor, erase } = require_src();
var { style, figures, clear, lines } = require_util2();
var isNumber = /[0-9]/;
var isDef = (any) => any !== undefined;
var round = (number, precision) => {
let factor = Math.pow(10, precision);
return Math.round(number * factor) / factor;
};
class NumberPrompt extends Prompt {
constructor(opts = {}) {
super(opts);
this.transform = style.render(opts.style);
this.msg = opts.message;
this.initial = isDef(opts.initial) ? opts.initial : "";
this.float = !!opts.float;
this.round = opts.round || 2;
this.inc = opts.increment || 1;
this.min = isDef(opts.min) ? opts.min : -Infinity;
this.max = isDef(opts.max) ? opts.max : Infinity;
this.errorMsg = opts.error || `Please Enter A Valid Value`;
this.validator = opts.validate || (() => true);
this.color = `cyan`;
this.value = ``;
this.typed = ``;
this.lastHit = 0;
this.render();
}
set value(v) {
if (!v && v !== 0) {
this.placeholder = true;
this.rendered = color.gray(this.transform.render(`${this.initial}`));
this._value = ``;
} else {
this.placeholder = false;
this.rendered = this.transform.render(`${round(v, this.round)}`);
this._value = round(v, this.round);
}
this.fire();
}
get value() {
return this._value;
}
parse(x) {
return this.float ? parseFloat(x) : parseInt(x);
}
valid(c) {
return c === `-` || c === `.` && this.float || isNumber.test(c);
}
reset() {
this.typed = ``;
this.value = ``;
this.fire();
this.render();
}
exit() {
this.abort();
}
abort() {
let x = this.value;
this.value = x !== `` ? x : this.initial;
this.done = this.aborted = true;
this.error = false;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
async validate() {
let valid = await this.validator(this.value);
if (typeof valid === `string`) {
this.errorMsg = valid;
valid = false;
}
this.error = !valid;
}
async submit() {
await this.validate();
if (this.error) {
this.color = `red`;
this.fire();
this.render();
return;
}
let x = this.value;
this.value = x !== `` ? x : this.initial;
this.done = true;
this.aborted = false;
this.error = false;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
up() {
this.typed = ``;
if (this.value === "") {
this.value = this.min - this.inc;
}
if (this.value >= this.max)
return this.bell();
this.value += this.inc;
this.color = `cyan`;
this.fire();
this.render();
}
down() {
this.typed = ``;
if (this.value === "") {
this.value = this.min + this.inc;
}
if (this.value <= this.min)
return this.bell();
this.value -= this.inc;
this.color = `cyan`;
this.fire();
this.render();
}
delete() {
let val = this.value.toString();
if (val.length === 0)
return this.bell();
this.value = this.parse(val = val.slice(0, -1)) || ``;
if (this.value !== "" && this.value < this.min) {
this.value = this.min;
}
this.color = `cyan`;
this.fire();
this.render();
}
next() {
this.value = this.initial;
this.fire();
this.render();
}
_(c, key) {
if (!this.valid(c))
return this.bell();
const now = Date.now();
if (now - this.lastHit > 1000)
this.typed = ``;
this.typed += c;
this.lastHit = now;
this.color = `cyan`;
if (c === `.`)
return this.fire();
this.value = Math.min(this.parse(this.typed), this.max);
if (this.value > this.max)
this.value = this.max;
if (this.value < this.min)
this.value = this.min;
this.fire();
this.render();
}
render() {
if (this.closed)
return;
if (!this.firstRender) {
if (this.outputError)
this.out.write(cursor.down(lines(this.outputError, this.out.columns) - 1) + clear(this.outputError, this.out.columns));
this.out.write(clear(this.outputText, this.out.columns));
}
super.render();
this.outputError = "";
this.outputText = [
style.symbol(this.done, this.aborted),
color.bold(this.msg),
style.delimiter(this.done),
!this.done || !this.done && !this.placeholder ? color[this.color]().underline(this.rendered) : this.rendered
].join(` `);
if (this.error) {
this.outputError += this.errorMsg.split(`
`).reduce((a, l, i) => a + `
${i ? ` ` : figures.pointerSmall} ${color.red().italic(l)}`, ``);
}
this.out.write(erase.line + cursor.to(0) + this.outputText + cursor.save + this.outputError + cursor.restore);
}
}
module.exports = NumberPrompt;
});
// node_modules/prompts/lib/elements/multiselect.js
var require_multiselect2 = __commonJS((exports, module) => {
var color = require_kleur();
var { cursor } = require_src();
var Prompt = require_prompt2();
var { clear, figures, style, wrap, entriesToDisplay } = require_util2();
class MultiselectPrompt extends Prompt {
constructor(opts = {}) {
super(opts);
this.msg = opts.message;
this.cursor = opts.cursor || 0;
this.scrollIndex = opts.cursor || 0;
this.hint = opts.hint || "";
this.warn = opts.warn || "- This option is disabled -";
this.minSelected = opts.min;
this.showMinError = false;
this.maxChoices = opts.max;
this.instructions = opts.instructions;
this.optionsPerPage = opts.optionsPerPage || 10;
this.value = opts.choices.map((ch, idx) => {
if (typeof ch === "string")
ch = { title: ch, value: idx };
return {
title: ch && (ch.title || ch.value || ch),
description: ch && ch.description,
value: ch && (ch.value === undefined ? idx : ch.value),
selected: ch && ch.selected,
disabled: ch && ch.disabled
};
});
this.clear = clear("", this.out.columns);
if (!opts.overrideRender) {
this.render();
}
}
reset() {
this.value.map((v) => !v.selected);
this.cursor = 0;
this.fire();
this.render();
}
selected() {
return this.value.filter((v) => v.selected);
}
exit() {
this.abort();
}
abort() {
this.done = this.aborted = true;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
submit() {
const selected = this.value.filter((e) => e.selected);
if (this.minSelected && selected.length < this.minSelected) {
this.showMinError = true;
this.render();
} else {
this.done = true;
this.aborted = false;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
}
first() {
this.cursor = 0;
this.render();
}
last() {
this.cursor = this.value.length - 1;
this.render();
}
next() {
this.cursor = (this.cursor + 1) % this.value.length;
this.render();
}
up() {
if (this.cursor === 0) {
this.cursor = this.value.length - 1;
} else {
this.cursor--;
}
this.render();
}
down() {
if (this.cursor === this.value.length - 1) {
this.cursor = 0;
} else {
this.cursor++;
}
this.render();
}
left() {
this.value[this.cursor].selected = false;
this.render();
}
right() {
if (this.value.filter((e) => e.selected).length >= this.maxChoices)
return this.bell();
this.value[this.cursor].selected = true;
this.render();
}
handleSpaceToggle() {
const v = this.value[this.cursor];
if (v.selected) {
v.selected = false;
this.render();
} else if (v.disabled || this.value.filter((e) => e.selected).length >= this.maxChoices) {
return this.bell();
} else {
v.selected = true;
this.render();
}
}
toggleAll() {
if (this.maxChoices !== undefined || this.value[this.cursor].disabled) {
return this.bell();
}
const newSelected = !this.value[this.cursor].selected;
this.value.filter((v) => !v.disabled).forEach((v) => v.selected = newSelected);
this.render();
}
_(c, key) {
if (c === " ") {
this.handleSpaceToggle();
} else if (c === "a") {
this.toggleAll();
} else {
return this.bell();
}
}
renderInstructions() {
if (this.instructions === undefined || this.instructions) {
if (typeof this.instructions === "string") {
return this.instructions;
}
return `
Instructions:
` + ` ${figures.arrowUp}/${figures.arrowDown}: Highlight option
` + ` ${figures.arrowLeft}/${figures.arrowRight}/[space]: Toggle selection
` + (this.maxChoices === undefined ? ` a: Toggle all
` : "") + ` enter/return: Complete answer`;
}
return "";
}
renderOption(cursor2, v, i, arrowIndicator) {
const prefix = (v.selected ? color.green(figures.radioOn) : figures.radioOff) + " " + arrowIndicator + " ";
let title, desc;
if (v.disabled) {
title = cursor2 === i ? color.gray().underline(v.title) : color.strikethrough().gray(v.title);
} else {
title = cursor2 === i ? color.cyan().underline(v.title) : v.title;
if (cursor2 === i && v.description) {
desc = ` - ${v.description}`;
if (prefix.length + title.length + desc.length >= this.out.columns || v.description.split(/\r?\n/).length > 1) {
desc = `
` + wrap(v.description, { margin: prefix.length, width: this.out.columns });
}
}
}
return prefix + title + color.gray(desc || "");
}
paginateOptions(options) {
if (options.length === 0) {
return color.red("No matches for this query.");
}
let { startIndex, endIndex } = entriesToDisplay(this.cursor, options.length, this.optionsPerPage);
let prefix, styledOptions = [];
for (let i = startIndex;i < endIndex; i++) {
if (i === startIndex && startIndex > 0) {
prefix = figures.arrowUp;
} else if (i === endIndex - 1 && endIndex < options.length) {
prefix = figures.arrowDown;
} else {
prefix = " ";
}
styledOptions.push(this.renderOption(this.cursor, options[i], i, prefix));
}
return `
` + styledOptions.join(`
`);
}
renderOptions(options) {
if (!this.done) {
return this.paginateOptions(options);
}
return "";
}
renderDoneOrInstructions() {
if (this.done) {
return this.value.filter((e) => e.selected).map((v) => v.title).join(", ");
}
const output = [color.gray(this.hint), this.renderInstructions()];
if (this.value[this.cursor].disabled) {
output.push(color.yellow(this.warn));
}
return output.join(" ");
}
render() {
if (this.closed)
return;
if (this.firstRender)
this.out.write(cursor.hide);
super.render();
let prompt = [
style.symbol(this.done, this.aborted),
color.bold(this.msg),
style.delimiter(false),
this.renderDoneOrInstructions()
].join(" ");
if (this.showMinError) {
prompt += color.red(`You must select a minimum of ${this.minSelected} choices.`);
this.showMinError = false;
}
prompt += this.renderOptions(this.value);
this.out.write(this.clear + prompt);
this.clear = clear(prompt, this.out.columns);
}
}
module.exports = MultiselectPrompt;
});
// node_modules/prompts/lib/elements/autocomplete.js
var require_autocomplete2 = __commonJS((exports, module) => {
var color = require_kleur();
var Prompt = require_prompt2();
var { erase, cursor } = require_src();
var { style, clear, figures, wrap, entriesToDisplay } = require_util2();
var getVal = (arr, i) => arr[i] && (arr[i].value || arr[i].title || arr[i]);
var getTitle = (arr, i) => arr[i] && (arr[i].title || arr[i].value || arr[i]);
var getIndex = (arr, valOrTitle) => {
const index = arr.findIndex((el) => el.value === valOrTitle || el.title === valOrTitle);
return index > -1 ? index : undefined;
};
class AutocompletePrompt extends Prompt {
constructor(opts = {}) {
super(opts);
this.msg = opts.message;
this.suggest = opts.suggest;
this.choices = opts.choices;
this.initial = typeof opts.initial === "number" ? opts.initial : getIndex(opts.choices, opts.initial);
this.select = this.initial || opts.cursor || 0;
this.i18n = { noMatches: opts.noMatches || "no matches found" };
this.fallback = opts.fallback || this.initial;
this.clearFirst = opts.clearFirst || false;
this.suggestions = [];
this.input = "";
this.limit = opts.limit || 10;
this.cursor = 0;
this.transform = style.render(opts.style);
this.scale = this.transform.scale;
this.render = this.render.bind(this);
this.complete = this.complete.bind(this);
this.clear = clear("", this.out.columns);
this.complete(this.render);
this.render();
}
set fallback(fb) {
this._fb = Number.isSafeInteger(parseInt(fb)) ? parseInt(fb) : fb;
}
get fallback() {
let choice;
if (typeof this._fb === "number")
choice = this.choices[this._fb];
else if (typeof this._fb === "string")
choice = { title: this._fb };
return choice || this._fb || { title: this.i18n.noMatches };
}
moveSelect(i) {
this.select = i;
if (this.suggestions.length > 0)
this.value = getVal(this.suggestions, i);
else
this.value = this.fallback.value;
this.fire();
}
async complete(cb) {
const p = this.completing = this.suggest(this.input, this.choices);
const suggestions = await p;
if (this.completing !== p)
return;
this.suggestions = suggestions.map((s, i, arr) => ({ title: getTitle(arr, i), value: getVal(arr, i), description: s.description }));
this.completing = false;
const l = Math.max(suggestions.length - 1, 0);
this.moveSelect(Math.min(l, this.select));
cb && cb();
}
reset() {
this.input = "";
this.complete(() => {
this.moveSelect(this.initial !== undefined ? this.initial : 0);
this.render();
});
this.render();
}
exit() {
if (this.clearFirst && this.input.length > 0) {
this.reset();
} else {
this.done = this.exited = true;
this.aborted = false;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
}
abort() {
this.done = this.aborted = true;
this.exited = false;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
submit() {
this.done = true;
this.aborted = this.exited = false;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
_(c, key) {
let s1 = this.input.slice(0, this.cursor);
let s2 = this.input.slice(this.cursor);
this.input = `${s1}${c}${s2}`;
this.cursor = s1.length + 1;
this.complete(this.render);
this.render();
}
delete() {
if (this.cursor === 0)
return this.bell();
let s1 = this.input.slice(0, this.cursor - 1);
let s2 = this.input.slice(this.cursor);
this.input = `${s1}${s2}`;
this.complete(this.render);
this.cursor = this.cursor - 1;
this.render();
}
deleteForward() {
if (this.cursor * this.scale >= this.rendered.length)
return this.bell();
let s1 = this.input.slice(0, this.cursor);
let s2 = this.input.slice(this.cursor + 1);
this.input = `${s1}${s2}`;
this.complete(this.render);
this.render();
}
first() {
this.moveSelect(0);
this.render();
}
last() {
this.moveSelect(this.suggestions.length - 1);
this.render();
}
up() {
if (this.select === 0) {
this.moveSelect(this.suggestions.length - 1);
} else {
this.moveSelect(this.select - 1);
}
this.render();
}
down() {
if (this.select === this.suggestions.length - 1) {
this.moveSelect(0);
} else {
this.moveSelect(this.select + 1);
}
this.render();
}
next() {
if (this.select === this.suggestions.length - 1) {
this.moveSelect(0);
} else
this.moveSelect(this.select + 1);
this.render();
}
nextPage() {
this.moveSelect(Math.min(this.select + this.limit, this.suggestions.length - 1));
this.render();
}
prevPage() {
this.moveSelect(Math.max(this.select - this.limit, 0));
this.render();
}
left() {
if (this.cursor <= 0)
return this.bell();
this.cursor = this.cursor - 1;
this.render();
}
right() {
if (this.cursor * this.scale >= this.rendered.length)
return this.bell();
this.cursor = this.cursor + 1;
this.render();
}
renderOption(v, hovered, isStart, isEnd) {
let desc;
let prefix = isStart ? figures.arrowUp : isEnd ? figures.arrowDown : " ";
let title = hovered ? color.cyan().underline(v.title) : v.title;
prefix = (hovered ? color.cyan(figures.pointer) + " " : " ") + prefix;
if (v.description) {
desc = ` - ${v.description}`;
if (prefix.length + title.length + desc.length >= this.out.columns || v.description.split(/\r?\n/).length > 1) {
desc = `
` + wrap(v.description, { margin: 3, width: this.out.columns });
}
}
return prefix + " " + title + color.gray(desc || "");
}
render() {
if (this.closed)
return;
if (this.firstRender)
this.out.write(cursor.hide);
else
this.out.write(clear(this.outputText, this.out.columns));
super.render();
let { startIndex, endIndex } = entriesToDisplay(this.select, this.choices.length, this.limit);
this.outputText = [
style.symbol(this.done, this.aborted, this.exited),
color.bold(this.msg),
style.delimiter(this.completing),
this.done && this.suggestions[this.select] ? this.suggestions[this.select].title : this.rendered = this.transform.render(this.input)
].join(" ");
if (!this.done) {
const suggestions = this.suggestions.slice(startIndex, endIndex).map((item, i) => this.renderOption(item, this.select === i + startIndex, i === 0 && startIndex > 0, i + startIndex === endIndex - 1 && endIndex < this.choices.length)).join(`
`);
this.outputText += `
` + (suggestions || color.gray(this.fallback.title));
}
this.out.write(erase.line + cursor.to(0) + this.outputText);
}
}
module.exports = AutocompletePrompt;
});
// node_modules/prompts/lib/elements/autocompleteMultiselect.js
var require_autocompleteMultiselect2 = __commonJS((exports, module) => {
var color = require_kleur();
var { cursor } = require_src();
var MultiselectPrompt = require_multiselect2();
var { clear, style, figures } = require_util2();
class AutocompleteMultiselectPrompt extends MultiselectPrompt {
constructor(opts = {}) {
opts.overrideRender = true;
super(opts);
this.inputValue = "";
this.clear = clear("", this.out.columns);
this.filteredOptions = this.value;
this.render();
}
last() {
this.cursor = this.filteredOptions.length - 1;
this.render();
}
next() {
this.cursor = (this.cursor + 1) % this.filteredOptions.length;
this.render();
}
up() {
if (this.cursor === 0) {
this.cursor = this.filteredOptions.length - 1;
} else {
this.cursor--;
}
this.render();
}
down() {
if (this.cursor === this.filteredOptions.length - 1) {
this.cursor = 0;
} else {
this.cursor++;
}
this.render();
}
left() {
this.filteredOptions[this.cursor].selected = false;
this.render();
}
right() {
if (this.value.filter((e) => e.selected).length >= this.maxChoices)
return this.bell();
this.filteredOptions[this.cursor].selected = true;
this.render();
}
delete() {
if (this.inputValue.length) {
this.inputValue = this.inputValue.substr(0, this.inputValue.length - 1);
this.updateFilteredOptions();
}
}
updateFilteredOptions() {
const currentHighlight = this.filteredOptions[this.cursor];
this.filteredOptions = this.value.filter((v) => {
if (this.inputValue) {
if (typeof v.title === "string") {
if (v.title.toLowerCase().includes(this.inputValue.toLowerCase())) {
return true;
}
}
if (typeof v.value === "string") {
if (v.value.toLowerCase().includes(this.inputValue.toLowerCase())) {
return true;
}
}
return false;
}
return true;
});
const newHighlightIndex = this.filteredOptions.findIndex((v) => v === currentHighlight);
this.cursor = newHighlightIndex < 0 ? 0 : newHighlightIndex;
this.render();
}
handleSpaceToggle() {
const v = this.filteredOptions[this.cursor];
if (v.selected) {
v.selected = false;
this.render();
} else if (v.disabled || this.value.filter((e) => e.selected).length >= this.maxChoices) {
return this.bell();
} else {
v.selected = true;
this.render();
}
}
handleInputChange(c) {
this.inputValue = this.inputValue + c;
this.updateFilteredOptions();
}
_(c, key) {
if (c === " ") {
this.handleSpaceToggle();
} else {
this.handleInputChange(c);
}
}
renderInstructions() {
if (this.instructions === undefined || this.instructions) {
if (typeof this.instructions === "string") {
return this.instructions;
}
return `
Instructions:
${figures.arrowUp}/${figures.arrowDown}: Highlight option
${figures.arrowLeft}/${figures.arrowRight}/[space]: Toggle selection
[a,b,c]/delete: Filter choices
enter/return: Complete answer
`;
}
return "";
}
renderCurrentInput() {
return `
Filtered results for: ${this.inputValue ? this.inputValue : color.gray("Enter something to filter")}
`;
}
renderOption(cursor2, v, i) {
let title;
if (v.disabled)
title = cursor2 === i ? color.gray().underline(v.title) : color.strikethrough().gray(v.title);
else
title = cursor2 === i ? color.cyan().underline(v.title) : v.title;
return (v.selected ? color.green(figures.radioOn) : figures.radioOff) + " " + title;
}
renderDoneOrInstructions() {
if (this.done) {
return this.value.filter((e) => e.selected).map((v) => v.title).join(", ");
}
const output = [color.gray(this.hint), this.renderInstructions(), this.renderCurrentInput()];
if (this.filteredOptions.length && this.filteredOptions[this.cursor].disabled) {
output.push(color.yellow(this.warn));
}
return output.join(" ");
}
render() {
if (this.closed)
return;
if (this.firstRender)
this.out.write(cursor.hide);
super.render();
let prompt = [
style.symbol(this.done, this.aborted),
color.bold(this.msg),
style.delimiter(false),
this.renderDoneOrInstructions()
].join(" ");
if (this.showMinError) {
prompt += color.red(`You must select a minimum of ${this.minSelected} choices.`);
this.showMinError = false;
}
prompt += this.renderOptions(this.filteredOptions);
this.out.write(this.clear + prompt);
this.clear = clear(prompt, this.out.columns);
}
}
module.exports = AutocompleteMultiselectPrompt;
});
// node_modules/prompts/lib/elements/confirm.js
var require_confirm2 = __commonJS((exports, module) => {
var color = require_kleur();
var Prompt = require_prompt2();
var { style, clear } = require_util2();
var { erase, cursor } = require_src();
class ConfirmPrompt extends Prompt {
constructor(opts = {}) {
super(opts);
this.msg = opts.message;
this.value = opts.initial;
this.initialValue = !!opts.initial;
this.yesMsg = opts.yes || "yes";
this.yesOption = opts.yesOption || "(Y/n)";
this.noMsg = opts.no || "no";
this.noOption = opts.noOption || "(y/N)";
this.render();
}
reset() {
this.value = this.initialValue;
this.fire();
this.render();
}
exit() {
this.abort();
}
abort() {
this.done = this.aborted = true;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
submit() {
this.value = this.value || false;
this.done = true;
this.aborted = false;
this.fire();
this.render();
this.out.write(`
`);
this.close();
}
_(c, key) {
if (c.toLowerCase() === "y") {
this.value = true;
return this.submit();
}
if (c.toLowerCase() === "n") {
this.value = false;
return this.submit();
}
return this.bell();
}
render() {
if (this.closed)
return;
if (this.firstRender)
this.out.write(cursor.hide);
else
this.out.write(clear(this.outputText, this.out.columns));
super.render();
this.outputText = [
style.symbol(this.done, this.aborted),
color.bold(this.msg),
style.delimiter(this.done),
this.done ? this.value ? this.yesMsg : this.noMsg : color.gray(this.initialValue ? this.yesOption : this.noOption)
].join(" ");
this.out.write(erase.line + cursor.to(0) + this.outputText);
}
}
module.exports = ConfirmPrompt;
});
// node_modules/prompts/lib/elements/index.js
var require_elements2 = __commonJS((exports, module) => {
module.exports = {
TextPrompt: require_text2(),
SelectPrompt: require_select2(),
TogglePrompt: require_toggle2(),
DatePrompt: require_date2(),
NumberPrompt: require_number2(),
MultiselectPrompt: require_multiselect2(),
AutocompletePrompt: require_autocomplete2(),
AutocompleteMultiselectPrompt: require_autocompleteMultiselect2(),
ConfirmPrompt: require_confirm2()
};
});
// node_modules/prompts/lib/prompts.js
var require_prompts2 = __commonJS((exports) => {
var $ = exports;
var el = require_elements2();
var noop = (v) => v;
function toPrompt(type, args, opts = {}) {
return new Promise((res, rej) => {
const p = new el[type](args);
const onAbort = opts.onAbort || noop;
const onSubmit = opts.onSubmit || noop;
const onExit = opts.onExit || noop;
p.on("state", args.onState || noop);
p.on("submit", (x) => res(onSubmit(x)));
p.on("exit", (x) => res(onExit(x)));
p.on("abort", (x) => rej(onAbort(x)));
});
}
$.text = (args) => toPrompt("TextPrompt", args);
$.password = (args) => {
args.style = "password";
return $.text(args);
};
$.invisible = (args) => {
args.style = "invisible";
return $.text(args);
};
$.number = (args) => toPrompt("NumberPrompt", args);
$.date = (args) => toPrompt("DatePrompt", args);
$.confirm = (args) => toPrompt("ConfirmPrompt", args);
$.list = (args) => {
const sep = args.separator || ",";
return toPrompt("TextPrompt", args, {
onSubmit: (str) => str.split(sep).map((s) => s.trim())
});
};
$.toggle = (args) => toPrompt("TogglePrompt", args);
$.select = (args) => toPrompt("SelectPrompt", args);
$.multiselect = (args) => {
args.choices = [].concat(args.choices || []);
const toSelected = (items) => items.filter((item) => item.selected).map((item) => item.value);
return toPrompt("MultiselectPrompt", args, {
onAbort: toSelected,
onSubmit: toSelected
});
};
$.autocompleteMultiselect = (args) => {
args.choices = [].concat(args.choices || []);
const toSelected = (items) => items.filter((item) => item.selected).map((item) => item.value);
return toPrompt("AutocompleteMultiselectPrompt", args, {
onAbort: toSelected,
onSubmit: toSelected
});
};
var byTitle = (input, choices) => Promise.resolve(choices.filter((item) => item.title.slice(0, input.length).toLowerCase() === input.toLowerCase()));
$.autocomplete = (args) => {
args.suggest = args.suggest || byTitle;
args.choices = [].concat(args.choices || []);
return toPrompt("AutocompletePrompt", args);
};
});
// node_modules/prompts/lib/index.js
var require_lib = __commonJS((exports, module) => {
var prompts = require_prompts2();
var passOn = ["suggest", "format", "onState", "validate", "onRender", "type"];
var noop = () => {};
async function prompt(questions = [], { onSubmit = noop, onCancel = noop } = {}) {
const answers = {};
const override2 = prompt._override || {};
questions = [].concat(questions);
let answer, question, quit, name, type, lastPrompt;
const getFormattedAnswer = async (question2, answer2, skipValidation = false) => {
if (!skipValidation && question2.validate && question2.validate(answer2) !== true) {
return;
}
return question2.format ? await question2.format(answer2, answers) : answer2;
};
for (question of questions) {
({ name, type } = question);
if (typeof type === "function") {
type = await type(answer, { ...answers }, question);
question["type"] = type;
}
if (!type)
continue;
for (let key in question) {
if (passOn.includes(key))
continue;
let value = question[key];
question[key] = typeof value === "function" ? await value(answer, { ...answers }, lastPrompt) : value;
}
lastPrompt = question;
if (typeof question.message !== "string") {
throw new Error("prompt message is required");
}
({ name, type } = question);
if (prompts[type] === undefined) {
throw new Error(`prompt type (${type}) is not defined`);
}
if (override2[question.name] !== undefined) {
answer = await getFormattedAnswer(question, override2[question.name]);
if (answer !== undefined) {
answers[name] = answer;
continue;
}
}
try {
answer = prompt._injected ? getInjectedAnswer(prompt._injected, question.initial) : await prompts[type](question);
answers[name] = answer = await getFormattedAnswer(question, answer, true);
quit = await onSubmit(question, answer, answers);
} catch (err) {
quit = !await onCancel(question, answers);
}
if (quit)
return answers;
}
return answers;
}
function getInjectedAnswer(injected, deafultValue) {
const answer = injected.shift();
if (answer instanceof Error) {
throw answer;
}
return answer === undefined ? deafultValue : answer;
}
function inject(answers) {
prompt._injected = (prompt._injected || []).concat(answers);
}
function override(answers) {
prompt._override = Object.assign({}, answers);
}
module.exports = Object.assign(prompt, { prompt, prompts, inject, override });
});
// node_modules/prompts/index.js
var require_prompts3 = __commonJS((exports, module) => {
function isNodeLT(tar) {
tar = (Array.isArray(tar) ? tar : tar.split(".")).map(Number);
let i = 0, src = process.versions.node.split(".").map(Number);
for (;i < tar.length; i++) {
if (src[i] > tar[i])
return false;
if (tar[i] > src[i])
return true;
}
return false;
}
module.exports = isNodeLT("8.6.0") ? require_dist() : require_lib();
});
// node_modules/chalk/source/vendor/ansi-styles/index.js
var ANSI_BACKGROUND_OFFSET = 10;
var wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
var wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`;
var wrapAnsi16m = (offset = 0) => (red, green, blue) => `\x1B[${38 + offset};2;${red};${green};${blue}m`;
var styles = {
modifier: {
reset: [0, 0],
bold: [1, 22],
dim: [2, 22],
italic: [3, 23],
underline: [4, 24],
overline: [53, 55],
inverse: [7, 27],
hidden: [8, 28],
strikethrough: [9, 29]
},
color: {
black: [30, 39],
red: [31, 39],
green: [32, 39],
yellow: [33, 39],
blue: [34, 39],
magenta: [35, 39],
cyan: [36, 39],
white: [37, 39],
blackBright: [90, 39],
gray: [90, 39],
grey: [90, 39],
redBright: [91, 39],
greenBright: [92, 39],
yellowBright: [93, 39],
blueBright: [94, 39],
magentaBright: [95, 39],
cyanBright: [96, 39],
whiteBright: [97, 39]
},
bgColor: {
bgBlack: [40, 49],
bgRed: [41, 49],
bgGreen: [42, 49],
bgYellow: [43, 49],
bgBlue: [44, 49],
bgMagenta: [45, 49],
bgCyan: [46, 49],
bgWhite: [47, 49],
bgBlackBright: [100, 49],
bgGray: [100, 49],
bgGrey: [100, 49],
bgRedBright: [101, 49],
bgGreenBright: [102, 49],
bgYellowBright: [103, 49],
bgBlueBright: [104, 49],
bgMagentaBright: [105, 49],
bgCyanBright: [106, 49],
bgWhiteBright: [107, 49]
}
};
var modifierNames = Object.keys(styles.modifier);
var foregroundColorNames = Object.keys(styles.color);
var backgroundColorNames = Object.keys(styles.bgColor);
var colorNames = [...foregroundColorNames, ...backgroundColorNames];
function assembleStyles() {
const codes = new Map;
for (const [groupName, group] of Object.entries(styles)) {
for (const [styleName, style] of Object.entries(group)) {
styles[styleName] = {
open: `\x1B[${style[0]}m`,
close: `\x1B[${style[1]}m`
};
group[styleName] = styles[styleName];
codes.set(style[0], style[1]);
}
Object.defineProperty(styles, groupName, {
value: group,
enumerable: false
});
}
Object.defineProperty(styles, "codes", {
value: codes,
enumerable: false
});
styles.color.close = "\x1B[39m";
styles.bgColor.close = "\x1B[49m";
styles.color.ansi = wrapAnsi16();
styles.color.ansi256 = wrapAnsi256();
styles.color.ansi16m = wrapAnsi16m();
styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
Object.defineProperties(styles, {
rgbToAnsi256: {
value(red, green, blue) {
if (red === green && green === blue) {
if (red < 8) {
return 16;
}
if (red > 248) {
return 231;
}
return Math.round((red - 8) / 247 * 24) + 232;
}
return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
},
enumerable: false
},
hexToRgb: {
value(hex) {
const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
if (!matches) {
return [0, 0, 0];
}
let [colorString] = matches;
if (colorString.length === 3) {
colorString = [...colorString].map((character) => character + character).join("");
}
const integer = Number.parseInt(colorString, 16);
return [
integer >> 16 & 255,
integer >> 8 & 255,
integer & 255
];
},
enumerable: false
},
hexToAnsi256: {
value: (hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
enumerable: false
},
ansi256ToAnsi: {
value(code) {
if (code < 8) {
return 30 + code;
}
if (code < 16) {
return 90 + (code - 8);
}
let red;
let green;
let blue;
if (code >= 232) {
red = ((code - 232) * 10 + 8) / 255;
green = red;
blue = red;
} else {
code -= 16;
const remainder = code % 36;
red = Math.floor(code / 36) / 5;
green = Math.floor(remainder / 6) / 5;
blue = remainder % 6 / 5;
}
const value = Math.max(red, green, blue) * 2;
if (value === 0) {
return 30;
}
let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
if (value === 2) {
result += 60;
}
return result;
},
enumerable: false
},
rgbToAnsi: {
value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
enumerable: false
},
hexToAnsi: {
value: (hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),
enumerable: false
}
});
return styles;
}
var ansiStyles = assembleStyles();
var ansi_styles_default = ansiStyles;
// node_modules/chalk/source/vendor/supports-color/index.js
import process2 from "process";
import os from "os";
import tty from "tty";
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process2.argv) {
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
const position = argv.indexOf(prefix + flag);
const terminatorPosition = argv.indexOf("--");
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
}
var { env } = process2;
var flagForceColor;
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
flagForceColor = 0;
} else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
flagForceColor = 1;
}
function envForceColor() {
if ("FORCE_COLOR" in env) {
if (env.FORCE_COLOR === "true") {
return 1;
}
if (env.FORCE_COLOR === "false") {
return 0;
}
return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
}
}
function translateLevel(level) {
if (level === 0) {
return false;
}
return {
level,
hasBasic: true,
has256: level >= 2,
has16m: level >= 3
};
}
function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
const noFlagForceColor = envForceColor();
if (noFlagForceColor !== undefined) {
flagForceColor = noFlagForceColor;
}
const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
if (forceColor === 0) {
return 0;
}
if (sniffFlags) {
if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
return 3;
}
if (hasFlag("color=256")) {
return 2;
}
}
if ("TF_BUILD" in env && "AGENT_NAME" in env) {
return 1;
}
if (haveStream && !streamIsTTY && forceColor === undefined) {
return 0;
}
const min = forceColor || 0;
if (env.TERM === "dumb") {
return min;
}
if (process2.platform === "win32") {
const osRelease = os.release().split(".");
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
return Number(osRelease[2]) >= 14931 ? 3 : 2;
}
return 1;
}
if ("CI" in env) {
if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => (key in env))) {
return 3;
}
if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => (sign in env)) || env.CI_NAME === "codeship") {
return 1;
}
return min;
}
if ("TEAMCITY_VERSION" in env) {
return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
}
if (env.COLORTERM === "truecolor") {
return 3;
}
if (env.TERM === "xterm-kitty") {
return 3;
}
if ("TERM_PROGRAM" in env) {
const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
switch (env.TERM_PROGRAM) {
case "iTerm.app": {
return version >= 3 ? 3 : 2;
}
case "Apple_Terminal": {
return 2;
}
}
}
if (/-256(color)?$/i.test(env.TERM)) {
return 2;
}
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
return 1;
}
if ("COLORTERM" in env) {
return 1;
}
return min;
}
function createSupportsColor(stream, options = {}) {
const level = _supportsColor(stream, {
streamIsTTY: stream && stream.isTTY,
...options
});
return translateLevel(level);
}
var supportsColor = {
stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
stderr: createSupportsColor({ isTTY: tty.isatty(2) })
};
var supports_color_default = supportsColor;
// node_modules/chalk/source/utilities.js
function stringReplaceAll(string, substring, replacer) {
let index = string.indexOf(substring);
if (index === -1) {
return string;
}
const substringLength = substring.length;
let endIndex = 0;
let returnValue = "";
do {
returnValue += string.slice(endIndex, index) + substring + replacer;
endIndex = index + substringLength;
index = string.indexOf(substring, endIndex);
} while (index !== -1);
returnValue += string.slice(endIndex);
return returnValue;
}
function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
let endIndex = 0;
let returnValue = "";
do {
const gotCR = string[index - 1] === "\r";
returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? `\r
` : `
`) + postfix;
endIndex = index + 1;
index = string.indexOf(`
`, endIndex);
} while (index !== -1);
returnValue += string.slice(endIndex);
return returnValue;
}
// node_modules/chalk/source/index.js
var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
var GENERATOR = Symbol("GENERATOR");
var STYLER = Symbol("STYLER");
var IS_EMPTY = Symbol("IS_EMPTY");
var levelMapping = [
"ansi",
"ansi",
"ansi256",
"ansi16m"
];
var styles2 = Object.create(null);
var applyOptions = (object, options = {}) => {
if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
throw new Error("The `level` option should be an integer from 0 to 3");
}
const colorLevel = stdoutColor ? stdoutColor.level : 0;
object.level = options.level === undefined ? colorLevel : options.level;
};
var chalkFactory = (options) => {
const chalk = (...strings) => strings.join(" ");
applyOptions(chalk, options);
Object.setPrototypeOf(chalk, createChalk.prototype);
return chalk;
};
function createChalk(options) {
return chalkFactory(options);
}
Object.setPrototypeOf(createChalk.prototype, Function.prototype);
for (const [styleName, style] of Object.entries(ansi_styles_default)) {
styles2[styleName] = {
get() {
const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
Object.defineProperty(this, styleName, { value: builder });
return builder;
}
};
}
styles2.visible = {
get() {
const builder = createBuilder(this, this[STYLER], true);
Object.defineProperty(this, "visible", { value: builder });
return builder;
}
};
var getModelAnsi = (model, level, type, ...arguments_) => {
if (model === "rgb") {
if (level === "ansi16m") {
return ansi_styles_default[type].ansi16m(...arguments_);
}
if (level === "ansi256") {
return ansi_styles_default[type].ansi256(ansi_styles_default.rgbToAnsi256(...arguments_));
}
return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
}
if (model === "hex") {
return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_));
}
return ansi_styles_default[type][model](...arguments_);
};
var usedModels = ["rgb", "hex", "ansi256"];
for (const model of usedModels) {
styles2[model] = {
get() {
const { level } = this;
return function(...arguments_) {
const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]);
return createBuilder(this, styler, this[IS_EMPTY]);
};
}
};
const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
styles2[bgModel] = {
get() {
const { level } = this;
return function(...arguments_) {
const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]);
return createBuilder(this, styler, this[IS_EMPTY]);
};
}
};
}
var proto = Object.defineProperties(() => {}, {
...styles2,
level: {
enumerable: true,
get() {
return this[GENERATOR].level;
},
set(level) {
this[GENERATOR].level = level;
}
}
});
var createStyler = (open, close, parent) => {
let openAll;
let closeAll;
if (parent === undefined) {
openAll = open;
closeAll = close;
} else {
openAll = parent.openAll + open;
closeAll = close + parent.closeAll;
}
return {
open,
close,
openAll,
closeAll,
parent
};
};
var createBuilder = (self, _styler, _isEmpty) => {
const builder = (...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" "));
Object.setPrototypeOf(builder, proto);
builder[GENERATOR] = self;
builder[STYLER] = _styler;
builder[IS_EMPTY] = _isEmpty;
return builder;
};
var applyStyle = (self, string) => {
if (self.level <= 0 || !string) {
return self[IS_EMPTY] ? "" : string;
}
let styler = self[STYLER];
if (styler === undefined) {
return string;
}
const { openAll, closeAll } = styler;
if (string.includes("\x1B")) {
while (styler !== undefined) {
string = stringReplaceAll(string, styler.close, styler.open);
styler = styler.parent;
}
}
const lfIndex = string.indexOf(`
`);
if (lfIndex !== -1) {
string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
}
return openAll + string + closeAll;
};
Object.defineProperties(createChalk.prototype, styles2);
var chalk = createChalk();
var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
var source_default = chalk;
// src/index.ts
var import_prompts7 = __toESM(require_prompts3(), 1);
// src/commands/init.ts
var import_prompts6 = __toESM(require_prompts3(), 1);
// src/commands/init/typescript.ts
var import_prompts = __toESM(require_prompts3(), 1);
import { writeFile, exists, mkdir } from "fs/promises";
import path from "path";
import { join } from "path";
// src/templates/readme/typescript.ts
var generateTypeScriptReadme = (projectName, framework, database, useSrcDir, mongoDriver) => {
const mongoDriverInfo = database === "mongodb" && mongoDriver ? `
### MongoDB Driver: ${mongoDriver === "mongoose" ? "Mongoose \uD83D\uDC00" : "MongoDB Native \uD83C\uDF43"}` : "";
const schemaInfo = database === "mongodb" && mongoDriver === "mongoose" ? `${useSrcDir ? "\u2502 " : ""}\u2502 \u251C\u2500\u2500 [name].schema.ts # Mongoose schema/model` : `${useSrcDir ? "\u2502 " : ""}\u2502 \u251C\u2500\u2500 [name].schema.ts # Data schema/model`;
const repoInfo = database === "mongodb" && mongoDriver === "mongoose" ? "" : `${useSrcDir ? "\u2502 " : ""}\u2502 \u251C\u2500\u2500 [name].repository.ts # Data access layer
`;
return `# ${projectName}
## \uD83D\uDE80 Project Structure
\`\`\`
${projectName}/
${useSrcDir ? "\u251C\u2500\u2500 src/" : ""}
${useSrcDir ? "\u2502 " : ""}\u251C\u2500\u2500 config/ # Database configuration
${useSrcDir ? "\u2502 " : ""}\u2502 \u251C\u2500\u2500 db.json # Database credentials
${useSrcDir ? "\u2502 " : ""}\u2502 \u2514\u2500\u2500 index.ts # Config loader
${useSrcDir ? "\u2502 " : ""}\u251C\u2500\u2500 modules/ # Business modules
${useSrcDir ? "\u2502 " : ""}\u2502 \u2514\u2500\u2500 [module]/ # Specific module
${schemaInfo}
${repoInfo}${useSrcDir ? "\u2502 " : ""}\u2502 \u251C\u2500\u2500 [name].service.ts # Business logic
${useSrcDir ? "\u2502 " : ""}\u2502 \u251C\u2500\u2500 [name].migrate.ts # Database migrations
${useSrcDir ? "\u2502 " : ""}\u2502 \u251C\u2500\u2500 [name].seed.ts # Data seeder
${useSrcDir ? "\u2502 " : ""}\u2502 \u2514\u2500\u2500 index.ts # Controller/routes
${useSrcDir ? "\u2502 " : ""}\u251C\u2500\u2500 router.ts # API routes configuration
${useSrcDir ? "\u2502 " : ""}\u251C\u2500\u2500 error.ts # Error handling
${useSrcDir ? "\u2502 " : ""}\u2514\u2500\u2500 index.ts # Application entry point
\u251C\u2500\u2500 data/ # Sample data for seeding
\u2502 \u2514\u2500\u2500 [resources].json # JSON data for each resource
\u251C\u2500\u2500 henotic.config.json # Henotic configuration
\u2514\u2500\u2500 package.json # Project dependencies
\`\`\`${mongoDriverInfo}
## \uD83D\uDEE0\uFE0F Commands
### Generate CRUD
Generate a new CRUD module:
\`\`\`bash
henotic generate Product name:string price:number description:string
\`\`\`
### Run the application
# Development mode
\`\`\`bash
henotic dev
\`\`\`
# Production mode
\`\`\`bash
henotic start
\`\`\`
### Build the application
\`\`\`bash
henotic build
\`\`\`
### Seed the database
\`\`\`bash
# Seed a specific module
henotic seed Product
\`\`\`
or
\`\`\`bash
# Seed all modules
henotic seed --all
\`\`\`
### Unseed the database
\`\`\`bash
# Remove seed data for a specific module
henotic unseed Product
\`\`\`
or
\`\`\`bash
# Remove seed data for all modules
henotic unseed --all
\`\`\`
### Database migrations
\`\`\`bash
# Run migrations for a specific module
henotic migrate Product
\`\`\`
or
\`\`\`bash
# Run migrations for all modules
henotic migrate --all
\`\`\`
### Drop tables
\`\`\`bash
# Drop tables for a specific module
henotic drop Product
\`\`\`
or
\`\`\`bash
# Drop tables for all modules
henotic drop --all
\`\`\`
## \uD83D\uDCDA API Endpoints
After generating a module, the following endpoints will be available:
- **GET** \`/api/[resources]\`: Get all resources
- **GET** \`/api/[resources]/:id\`: Get a resource by ID
- **POST** \`/api/[resources]\`: Create a new resource
- **PUT** \`/api/[resources]/:id\`: Update a resource
- **DELETE** \`/api/[resources]/:id\`: Delete a resource
## \uD83D\uDD27 Configuration
Edit the \`config/db.json\` file to configure your database connection and other settings.
${framework === "next" ? `## Next.js Specific
This project uses Next.js App Router. API routes are located in \`app/api/[resource]/route.ts\`.` : ""}
`;
};
// src/commands/init/typescript.ts
var promptsConfig = {
onCancel: () => {
console.log(source_default.yellow(`
\uD83D\uDED1 Operasi dibatalkan oleh pengguna`));
process.exit(0);
}
};
async function initTypeScript(projectName) {
const frameworkChoices = [
{ title: "Express.js \uD83D\uDE80", value: "express" },
{ title: "Elysia (Bun) \uD83D\uDC30", value: "elysia", disabled: true },
{ title: "Hono \uD83D\uDD25", value: "hono" },
{ title: "Next.js \u23ED\uFE0F", value: "next" }
];
let framework;
if (frameworkChoices.length > 1) {
const response = await import_prompts.default({
type: "select",
name: "framework",
message: "Pilih framework:",
choices: frameworkChoices
}, promptsConfig);
if (!response.framework) {
console.log(source_default.yellow(`
\uD83D\uDED1 Operasi dibatalkan oleh pengguna`));
process.exit(0);
}
framework = response.framework;
} else {
framework = frameworkChoices[0]?.value ?? "native";
console.log(`Framework otomatis: ${framework}`);
}
let dbChoices = [
{ title: "PostgreSQL \uD83D\uDC18", value: "postgresql" },
{ title: "MariaDB \uD83D\uDC2C", value: "mariadb", disabled: true },
{ title: "SQLite \uD83D\uDCC1", value: "sqlite" },
{ title: "MongoDB \uD83C\uDF43", value: "mongodb" }
];
if (framework === "next") {
dbChoices = dbChoices.map((choice) => ({
...choice,
disabled: choice.value !== "mongodb"
}));
}
const dbResponse = await import_prompts.default({
type: "select",
name: "database",
message: "Pilih database:",
choices: dbChoices
}, promptsConfig);
if (!dbResponse.database) {
console.log(source_default.yellow(`
\uD83D\uDED1 Operasi dibatalkan oleh pengguna`));
process.exit(0);
}
const database = dbResponse.database;
let mongoDriver;
if (database === "mongodb") {
const driverResponse = await import_prompts.default({
type: "select",
name: "driver",
message: "Pilih MongoDB driver:",
choices: [
{ title: "Mongoose \uD83D\uDC00 (ODM dengan schema)", value: "mongoose" },
{ title: "MongoDB Native \uD83C\uDF43 (driver resmi)", value: "mongodb" }
]
}, promptsConfig);
if (!driverResponse.driver) {
console.log(source_default.yellow(`
\uD83D\uDED1 Operasi dibatalkan oleh pengguna`));
process.exit(0);
}
mongoDriver = driverResponse.driver;
}
let useSrcDir = true;
if (framework !== "next") {
const dirResponse = await import_prompts.default({
type: "confirm",
name: "useSrcDir",
message: "Gunakan folder src/ sebagai project directory?",
initial: true
}, promptsConfig);
if (dirResponse.useSrcDir === undefined) {
console.log(source_default.yellow(`
\uD83D\uDED1 Operasi dibatalkan oleh pengguna`));
process.exit(0);
}
useSrcDir = dirResponse.useSrcDir;
}
if (projectName !== ".") {
const dirExists = await exists(projectName);
if (!dirExists) {
await mkdir(projectName, { recursive: true });
}
process.chdir(projectName);
}
if (framework !== "next") {
console.log(source_default.cyan(`
\uD83D\uDE80 Initializing TypeScript project...`));
const initProcess = Bun.spawn(["bun", "init", "-y"], {
stdio: ["ignore", "ignore", "ignore"]
});
await initProcess.exited;
if (initProcess.exitCode !== 0) {
throw new Error("Gagal menjalankan bun init -y");
}
}
const config = {
language: "typescript",
framework,
database,
projectDir: useSrcDir ? "src" : ""
};
if (mongoDriver) {
config.mongoDriver = mongoDriver;
}
if (framework === "next") {
console.log(source_default.cyan(`
\uD83D\uDE80 Initializing Next.js project...`));
const createProcess = Bun.spawn([
"bun",
"create",
"next-app",
".",
"--ts",
"--eslint",
"--tailwind",
"--src-dir",
"--app",
"--turbopack",
"--import-alias",
"@/*",
"--use-bun"
], {
stdio: ["inherit", "inherit", "inherit"]
});
await createProcess.exited;
if (createProcess.exitCode !== 0) {
throw new Error("Gagal membuat Next.js project");
}
console.log(source_default.green("\u2705 Next.js project initialized!"));
}
console.log(source_default.cyan(`
\uD83D\uDCE6 Installing dependencies...`));
const frameworkDeps = {
express: {
prod: ["express", "cors"],
dev: ["@types/express", "@types/cors"]
},
elysia: {
prod: ["elysia", "@elysiajs/cors", "@elysiajs/swagger"],
dev: []
},
hono: {
prod: ["hono", "@hono/zod-validator"],
dev: []
},
next: {
prod: [],
dev: []
}
};
const dbDeps = {
postgresql: {
prod: [],
dev: []
},
mongodb: {
prod: ["mongodb"],
dev: []
},
mariadb: {
prod: ["mariadb"],
dev: []
},
sqlite: {
prod: [],
dev: []
}
};
if (mongoDriver === "mongoose") {
dbDeps.mongodb.prod.push("mongoose");
}
const prodDeps = [
...frameworkDeps[framework].prod,
...dbDeps[database].prod,
"zod",
"dotenv"
];
const devDeps = [
...frameworkDeps[framework].dev,
...dbDeps[database].dev
];
if (prodDeps.length > 0) {
await Bun.spawn(["bun", "add", ...prodDeps], {
stdio: ["inherit", "inherit", "inherit"]
}).exited;
}
if (devDeps.length > 0) {
await Bun.spawn(["bun", "add", "-d", ...devDeps], {
stdio: ["inherit", "inherit", "inherit"]
}).exited;
}
if (prodDeps.length > 0 || devDeps.length > 0) {
console.log(source_default.green("\u2705 Dependencies terinstall!"));
}
const readmeContent = generateTypeScriptReadme(projectName === "." ? path.basename(process.cwd()) : projectName, framework, database, useSrcDir, mongoDriver);
await writeFile(join(process.cwd(), "README.md"), readmeContent);
await writeFile(join(process.cwd(), "henotic.config.json"), JSON.stringify(config, null, 2));
}
// src/commands/init/golang.ts
var import_prompts2 = __toESM(require_prompts3(), 1);
import { writeFile as writeFile2, exists as exists2, mkdir as mkdir2 } from "fs/promises";
import path2 from "path";
import { join as join2 } from "path";
// src/templates/readme/go.ts
var generateGoReadme = (projectName) => `# ${projectName}
## \uD83D\uDE80 Project Structure
\`\`\`
${projectName}/
\u251C\u2500\u2500 cmd/ # Command-line applications
\u2502 \u251C\u2500\u2500 main/ # Main application
\u2502 \u2502 \u2514\u2500\u2500 main.go # Entry point
\u2502 \u2514\u2500\u2500 seed/ # Database seeder
\u2502 \u2514\u2500\u2500 main.go # Seeder entry point
\u251C\u2500\u2500 data/ # Sample data for seeding
\u251C\u2500\u2500 internal/ # Private application code
\u2502 \u251C\u2500\u2500 module/ # Business modules
\u2502 \u2502 \u2514\u2500\u2500 [module]/ # Specific module
\u2502 \u2502 \u251C\u2500\u2500 entity/ # Domain models
\u2502 \u2502 \u251C\u2500\u2500 handler/ # HTTP handlers
\u2502 \u2502 \u2514\u2500\u2500 service/ # Business logic
\u2502 \u2502
\u2502 \u2514\u2500\u2500 seed/ # Seed implementations
\u251C\u2500\u2500 pkg/ # Public libraries
\u2502 \u251C\u2500\u2500 config/ # Configuration
\u2502 \u251C\u2500\u2500 database/ # Database connection
\u2502 \u251C\u2500\u2500 middleware/ # HTTP middleware
\u2502 \u2514\u2500\u2500 utils/ # Utility functions
\u251C\u2500\u2500 .env # Environment variables
\u251C\u2500\u2500 .gitignore # Git ignore file
\u251C\u2500\u2500 go.mod # Go modules
\u2514\u2500\u2500 go.sum # Go dependencies checksum
\`\`\`
## \uD83D\uDEE0\uFE0F Commands
### Generate CRUD
Generate a new CRUD module:
\`\`\`bash
henotic generate Product name:string price:number description:text
\`\`\`
### Run the application
Before running the application, you need to install the dependencies:
\`\`\`bash
go mod tidy
\`\`\`
Then, you can run the application:
\`\`\`bash
go run cmd/main/main.go
\`\`\`
or
\`\`\`bash
henotic start
\`\`\`
### Run the application in development mode
\`\`\`bash
henotic dev
\`\`\`
### Seed the database
\`\`\`bash
go run cmd/seed/main.go
\`\`\`
or
\`\`\`bash
henotic seed
\`\`\`
## \uD83D\uDCDA API Endpoints
After generating a module, the following endpoints will be available:
- **GET** \`/api/[resources]\`: Get all resources
- **GET** \`/api/[resources]/:id\`: Get a resource by ID
- **POST** \`/api/[resources]\`: Create a new resource
- **PUT** \`/api/[resources]/:id\`: Update a resource
- **DELETE** \`/api/[resources]/:id\`: Delete a resource
## \uD83D\uDD27 Configuration
Edit the \`.env\` file to configure your database connection and other settings.
`;
// src/commands/init/golang.ts
var promptsConfig2 = {
onCancel: () => {
console.log(source_default.yellow(`
\uD83D\uDED1 Operasi dibatalkan oleh pengguna`));
process.exit(0);
}
};
async function initGolang(projectName) {
const { database } = await import_prompts2.default({
type: "select",
name: "database",
message: "Pilih database:",
choices: [
{ title: "PostgreSQL \uD83D\uDC18", value: "postgresql" },
{ title: "MariaDB \uD83D\uDC2C", value: "mariadb" },
{ title: "SQLite \uD83D\uDCC1", value: "sqlite" },
{ title: "MongoDB \uD83C\uDF43", value: "mongodb", disabled: true }
]
}, promptsConfig2);
if (!database) {
console.log(source_default.yellow(`
\uD83D\uDED1 Operasi dibatalkan oleh pengguna`));
process.exit(0);
}
const config = {
language: "golang",
framework: "gin",
database,
projectDir: ""
};
console.log(source_default.cyan(`
\uD83D\uDE80 Initializing Go project...`));
if (projectName !== ".") {
const dirExists = await exists2(projectName);
if (!dirExists) {
await mkdir2(projectName, { recursive: true });
}
process.chdir(projectName);
}
const goModName = projectName === "." ? path2.basename(process.cwd()) : projectName;
const goInitProcess = Bun.spawn(["go", "mod", "init", goModName], {
stdio: ["inherit", "inherit", "inherit"]
});
await goInitProcess.exited;
console.log(source_default.green("\u2705 Go module initialized!"));
console.log(source_default.cyan(`
\uD83D\uDCE6 Installing Go dependencies...`));
const baseDeps = [
"github.com/gin-gonic/gin",
"github.com/go-playground/validator/v10",
"github.com/joho/godotenv"
];
const dbDeps = {
postgresql: [
"gorm.io/gorm",
"gorm.io/driver/postgres"
],
mongodb: [
"go.mongodb.org/mongo-driver"
],
mariadb: [
"gorm.io/gorm",
"gorm.io/driver/mysql"
],
sqlite: [
"gorm.io/gorm",
"gorm.io/driver/sqlite"
]
};
const goDeps = [...baseDeps, ...dbDeps[database] || []];
for (const dep of goDeps) {
console.log(source_default.cyan(`\uD83D\uDCE6 Installing ${dep}...`));
const goGetProcess = Bun.spawn(["go", "get", dep], {
stdio: ["inherit", "inherit", "inherit"]
});
await goGetProcess.exited;
if (goGetProcess.exitCode !== 0) {
console.log(source_default.yellow(`\u26A0\uFE0F Gagal menginstall ${dep}`));
}
}
console.log(source_default.cyan("\uD83E\uDDF9 Cleaning up dependencies..."));
await Bun.spawn(["go", "mod", "tidy"], {
stdio: ["inherit", "inherit", "inherit"]
}).exited;
console.log(source_default.green("\u2705 Go dependencies terinstall!"));
await mkdir2(join2(process.cwd(), "cmd", "main"), { recursive: true });
await mkdir2(join2(process.cwd(), "cmd", "seed"), { recursive: true });
await mkdir2(join2(process.cwd(), "internal", "module"), { recursive: true });
await mkdir2(join2(process.cwd(), "internal", "seed"), { recursive: true });
await mkdir2(join2(process.cwd(), "pkg", "config"), { recursive: true });
await mkdir2(join2(process.cwd(), "pkg", "database"), { recursive: true });
await mkdir2(join2(process.cwd(), "pkg", "middleware"), { recursive: true });
await mkdir2(join2(process.cwd(), "pkg", "utils"), { recursive: true });
await mkdir2(join2(process.cwd(), "data"), { recursive: true });
const readmeContent = generateGoReadme(goModName);
await writeFile2(join2(process.cwd(), "README.md"), readmeContent);
const gitignoreContent = `# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with 'go test -c'
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/
# Go workspace file
go.work
# Environment variables
.env
# Database files
*.db
`;
await writeFile2(join2(process.cwd(), ".gitignore"), gitignoreContent);
await writeFile2(join2(process.cwd(), "henotic.config.json"), JSON.stringify(config, null, 2));
}
// src/commands/init/java.ts
var import_prompts3 = __toESM(require_prompts3(), 1);
import { writeFile as writeFile3 } from "fs/promises";
import { join as join3 } from "path";
async function initJava(projectName) {
const { database } = await import_prompts3.default({
type: "select",
name: "database",
message: "Pilih database:",
choices: [
{ title: "PostgreSQL \uD83D\uDC18", value: "postgresql" },
{ title: "MongoDB \uD83C\uDF43", value: "mongodb" },
{ title: "MariaDB \uD83D\uDC2C", value: "mariadb" },
{ title: "MySQL \uD83D\uDC2C", value: "mysql" },
{ title: "SQLite \uD83D\uDCC1", value: "sqlite" }
]
});
console.log(source_default.yellow("\u26A0\uFE0F Java initialization belum diimplementasikan"));
const config = {
language: "java",
framework: "springboot",
database,
projectDir: ""
};
await writeFile3(join3(process.cwd(), "henotic.config.json"), JSON.stringify(config, null, 2));
}
// src/commands/init/php.ts
var import_prompts4 = __toESM(require_prompts3(), 1);
import { writeFile as writeFile4 } from "fs/promises";
import { join as join4 } from "path";
async function initPHP(projectName) {
const { database } = await import_prompts4.default({
type: "select",
name: "database",
message: "Pilih database:",
choices: [
{ title: "PostgreSQL \uD83D\uDC18", value: "postgresql" },
{ title: "MongoDB \uD83C\uDF43", value: "mongodb" },
{ title: "MariaDB \uD83D\uDC2C", value: "mariadb" },
{ title: "MySQL \uD83D\uDC2C", value: "mysql" },
{ title: "SQLite \uD83D\uDCC1", value: "sqlite" }
]
});
console.log(source_default.yellow("\u26A0\uFE0F PHP initialization belum diimplementasikan"));
const config = {
language: "php",
framework: "laravel",
database,
projectDir: ""
};
await writeFile4(join4(process.cwd(), "henotic.config.json"), JSON.stringify(config, null, 2));
}
// src/commands/init/rust.ts
var import_prompts5 = __toESM(require_prompts3(), 1);
import { writeFile as writeFile5, exists as exists3, mkdir as mkdir3 } from "fs/promises";
import { join as join5 } from "path";
import path3 from "path";
// src/templates/readme/rust.ts
function generateRustReadme(projectName, framework, database) {
return `# ${projectName}
Aplikasi Rust menggunakan ${framework} dan ${database}.
## Struktur Folder
\`\`\`
.
\u251C\u2500\u2500 src/
\u2502 \u251C\u2500\u2500 api/ # API layer (router, middleware)
\u2502 \u251C\u2500\u2500 core/ # Core functionality (database, config)
\u2502 \u251C\u2500\u2500 modules/ # Business modules
\u2502 \u2502 \u2514\u2500\u2500 product/ # Product module
\u2502 \u2514\u2500\u2500 bin/ # Binary executables
\u251C\u2500\u2500 migrations/ # Database migrations
\u2514\u2500\u2500 data/ # Seed data
\`\`\`
## Menjalankan Aplikasi
### Setup Database
1. Pastikan ${database} sudah terinstall dan berjalan
2. Jalankan migrasi database:
\`\`\`bash
sqlx migrate run
\`\`\`
### Menjalankan Aplikasi
\`\`\`bash
cargo run
\`\`\`
### Menjalankan Seeder
\`\`\`bash
cargo run --bin seed
\`\`\`
## Pengembangan
### Membuat Migrasi Baru
\`\`\`bash
sqlx migrate add <nama_migrasi>
\`\`\`
### Build untuk Production
\`\`\`bash
cargo build --release
\`\`\`
## Dibuat dengan Henotic CLI \uD83D\uDE80
`;
}
// src/commands/init/rust.ts
var promptsConfig3 = {
onCancel: () => {
console.log(source_default.yellow(`
\uD83D\uDED1 Operasi dibatalkan oleh pengguna`));
process.exit(0);
}
};
async function initRust(projectName) {
const { database } = await import_prompts5.default({
type: "select",
name: "database",
message: "Pilih database:",
choices: [
{ title: "PostgreSQL \uD83D\uDC18", value: "postgresql" },
{ title: "MariaDB \uD83D\uDC2C", value: "mariadb" },
{ title: "SQLite \uD83D\uDCC1", value: "sqlite" },
{ title: "MongoDB \uD83C\uDF43", value: "mongodb", disabled: true }
]
}, promptsConfig3);
if (!database) {
console.log(source_default.yellow(`
\uD83D\uDED1 Operasi dibatalkan oleh pengguna`));
process.exit(0);
}
const framework = "axum";
console.log(source_default.cyan(`Framework: ${framework} \uD83D\uDD04`));
console.log(source_default.cyan(`
\uD83D\uDE80 Initializing Rust project...`));
if (projectName !== ".") {
const dirExists = await exists3(projectName);
if (!dirExists) {
await mkdir3(projectName, { recursive: true });
}
process.chdir(projectName);
}
const cargoName = projectName === "." ? path3.basename(process.cwd()) : projectName;
console.log(source_default.cyan(`\uD83D\uDCE6 Creating new Rust project: ${cargoName}...`));
const cargoInitProcess = Bun.spawn(["cargo", "init", "--bin"], {
stdio: ["inherit", "inherit", "inherit"]
});
await cargoInitProcess.exited;
if (cargoInitProcess.exitCode !== 0) {
console.log(source_default.red("\u274C Cargo init gagal. Pastikan Rust terinstall dengan benar."));
process.exit(1);
}
console.log(source_default.green("\u2705 Rust project initialized!"));
console.log(source_default.cyan("\uD83D\uDCE6 Installing SQLx CLI..."));
const sqlxInstallProcess = Bun.spawn(["cargo", "install", "sqlx-cli"], {
stdio: ["inherit", "inherit", "inherit"]
});
await sqlxInstallProcess.exited;
if (sqlxInstallProcess.exitCode !== 0) {
console.log(source_default.yellow("\u26A0\uFE0F SQLx CLI installation failed, you may need to install it manually"));
} else {
console.log(source_default.green("\u2705 SQLx CLI installed!"));
}
console.log(source_default.cyan("\uD83D\uDCE6 Adding dependencies to Cargo.toml..."));
const baseDeps = [
["axum", "--features", "tokio"],
["tokio", "--features", "full"],
["serde", "--features", "derive"],
["serde_json"],
["chrono", "--features", "serde"],
["uuid", "--features", "v4,v7,serde"],
["dotenv"],
["anyhow"],
["thiserror"],
["async-trait"],
["validator", "--features", "derive"],
["hyper", "--features", "full"],
["include_dir"]
];
const dbFeatures = {
postgresql: "postgres,runtime-tokio-rustls,chrono,uuid,time",
mariadb: "mysql,runtime-tokio-rustls,chrono",
sqlite: "sqlite,migrate,runtime-tokio-rustls,uuid,chrono",
mongodb: "mongodb"
};
for (const dep of baseDeps) {
console.log(source_default.cyan(`\uD83D\uDCE6 Adding ${dep[0]}...`));
const addProcess = Bun.spawn(["cargo", "add", ...dep], {
stdio: ["inherit", "inherit", "inherit"]
});
await addProcess.exited;
if (addProcess.exitCode !== 0) {
console.log(source_default.yellow(`\u26A0\uFE0F Failed to add ${dep[0]}`));
}
}
if (database !== "mongodb") {
console.log(source_default.cyan(`\uD83D\uDCE6 Adding SQLx with ${database} features...`));
const sqlxAddProcess = Bun.spawn(["cargo", "add", "sqlx", "--features", dbFeatures[database]], {
stdio: ["inherit", "inherit", "inherit"]
});
await sqlxAddProcess.exited;
if (sqlxAddProcess.exitCode !== 0) {
console.log(source_default.yellow("\u26A0\uFE0F Failed to add SQLx"));
}
}
console.log(source_default.green("\u2705 Dependencies added!"));
console.log(source_default.cyan("\uD83D\uDCC1 Creating basic folder structure..."));
await mkdir3(join5(process.cwd(), "src", "api"), { recursive: true });
await mkdir3(join5(process.cwd(), "src", "core"), { recursive: true });
await mkdir3(join5(process.cwd(), "src", "modules"), { recursive: true });
await mkdir3(join5(process.cwd(), "src", "bin"), { recursive: true });
await mkdir3(join5(process.cwd(), "migrations"), { recursive: true });
await mkdir3(join5(process.cwd(), "data"), { recursive: true });
const files = [
{
path: "src/api/mod.rs",
content: "pub mod router;"
},
{
path: "src/api/router.rs",
content: ""
},
{
path: "src/bin/seed.rs",
content: ""
},
{
path: "src/core/mod.rs",
content: "pub mod db;"
},
{
path: "src/core/db.rs",
content: ""
},
{
path: "src/modules/mod.rs",
content: "// Modules will be added here"
},
{
path: "src/lib.rs",
content: `pub mod core;
pub mod api;
pub mod modules;
pub mod seed;`
},
{
path: "src/seed.rs",
content: ""
}
];
for (const file of files) {
await writeFile5(join5(process.cwd(), file.path), file.content);
}
let envContent = "";
if (database === "postgresql") {
envContent = `DATABASE_URL=postgres://postgres:postgres@localhost:5432/${cargoName}
SERVER_HOST=0.0.0.0:3000
`;
} else if (database === "mariadb") {
envContent = `DATABASE_URL=mysql://root:root@localhost:3306/${cargoName}
SERVER_HOST=0.0.0.0:3000
`;
} else if (database === "sqlite") {
envContent = `DATABASE_URL=sqlite:${cargoName}.db
SERVER_HOST=0.0.0.0:3000
`;
}
await writeFile5(join5(process.cwd(), ".env"), envContent);
let envexample = "";
if (database === "postgresql") {
envexample = `DATABASE_URL=postgres://postgres:postgres@localhost:5432/${cargoName}
SERVER_HOST=0.0.0.0:3000
`;
} else if (database === "mariadb") {
envexample = `DATABASE_URL=mysql://root:root@localhost:3306/${cargoName}
SERVER_HOST=0.0.0.0:3000
`;
} else if (database === "sqlite") {
envexample = `DATABASE_URL=sqlite:${cargoName}.db
SERVER_HOST=0.0.0.0:3000
`;
}
await writeFile5(join5(process.cwd(), ".env.example"), envexample);
const gitignoreContent = `# Generated by Cargo
/target/
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock
# These are backup files generated by rustfmt
**/*.rs.bk
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
# Environment variables
.env
# Database files
*.db
`;
await writeFile5(join5(process.cwd(), ".gitignore"), gitignoreContent);
const readmeContent = generateRustReadme(cargoName, framework, database);
await writeFile5(join5(process.cwd(), "README.md"), readmeContent);
console.log(source_default.green("\u2705 Project structure created!"));
const config = {
language: "rust",
framework,
database,
projectDir: "src"
};
await writeFile5(join5(process.cwd(), "henotic.config.json"), JSON.stringify(config, null, 2));
const rimrafProcess = Bun.spawn(["rm", "-rf", ".git", ".github"], {
stdio: ["inherit", "inherit", "inherit"]
});
await rimrafProcess.exited;
console.log(source_default.green(`
\u2728 Rust project initialized successfully!`));
console.log(source_default.cyan(`
\uD83D\uDCA1 Tip: Run the following commands to get started:`));
console.log(source_default.yellow("1. sqlx migrate add create_products_table"));
console.log(source_default.yellow("2. sqlx migrate run"));
console.log(source_default.yellow("3. cargo run"));
}
// src/commands/init.ts
var promptsConfig4 = {
onCancel: () => {
console.log(source_default.yellow(`
\uD83D\uDED1 Operasi dibatalkan oleh pengguna`));
process.exit(0);
}
};
async function init(projectName) {
const { language } = await import_prompts6.default({
type: "select",
name: "language",
message: "Pilih bahasa pemrograman:",
choices: [
{ title: "TypeScript \uD83D\uDC99", value: "typescript" },
{ title: "Golang \uD83E\uDDAB", value: "golang" },
{ title: "Java \u2615 (soon)", value: "java", disabled: true },
{ title: "PHP \uD83D\uDC18 (soon)", value: "php", disabled: true },
{ title: "Rust \uD83E\uDD80 (development)", value: "rust" }
]
}, promptsConfig4);
if (!language) {
console.log(source_default.yellow(`
\uD83D\uDED1 Operasi dibatalkan oleh pengguna`));
process.exit(0);
}
try {
if (language === "typescript") {
await initTypeScript(projectName);
} else if (language === "golang") {
await initGolang(projectName);
} else if (language === "java") {
await initJava(projectName);
} else if (language === "php") {
await initPHP(projectName);
} else if (language === "rust") {
await initRust(projectName);
}
console.log(source_default.green(`
\u2728 Project siap!`));
console.log("Langkah selanjutnya:");
if (language === "golang") {
if (projectName !== ".") {
console.log(`1. cd ${projectName}`);
console.log("2. henotic generate <model>");
console.log(source_default.cyan(`
\uD83D\uDCA1 Jangan lupa jalankan `) + source_default.yellow("go mod tidy") + source_default.cyan(" setelah generate model!"));
} else {
console.log("1. henotic generate <model>");
console.log(source_default.cyan(`
\uD83D\uDCA1 Jangan lupa jalankan `) + source_default.yellow("go mod tidy") + source_default.cyan(" setelah generate model!"));
}
} else {
if (projectName !== ".") {
console.log(`1. cd ${projectName}`);
console.log("2. henotic generate <model>");
} else {
console.log("1. henotic generate <model>");
}
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.error(source_default.red(`
\u274C Error: ${errorMessage}`));
process.exit(1);
}
}
// src/generators/utils/config.ts
import { join as join6 } from "path";
async function readConfig() {
try {
const configPath = join6(process.cwd(), "henotic.config.json");
const configFile = await Bun.file(configPath).json();
if (!configFile.language || !configFile.framework || !configFile.database) {
throw new Error("Config harus ada language, framework, dan database! \uD83D\uDEA8");
}
const config = {
language: configFile.language.toLowerCase(),
framework: configFile.framework.toLowerCase(),
database: configFile.database.toLowerCase(),
projectDir: configFile.projectDir || ""
};
if (config.database === "mongodb") {
return {
...config,
mongoDriver: configFile.mongoDriver || "mongoose"
};
}
return config;
} catch (error) {
throw new Error(`Gagal baca henotic.config.json: ${source_default.red(error.message)}`);
}
}
// src/generators/utils/plural.ts
function pluralize(word) {
const irregulars = {
Category: "Categories",
Property: "Properties",
City: "Cities",
Story: "Stories",
Baby: "Babies",
Person: "People",
Man: "Men",
Woman: "Women",
Child: "Children",
Tooth: "Teeth",
Foot: "Feet",
Mouse: "Mice",
Belief: "Beliefs"
};
if (irregulars[word]) {
return irregulars[word];
}
if (word.match(/[sxz]$/)) {
return word + "es";
}
if (word.match(/[^aeiou]y$/)) {
return word.replace(/y$/, "ies");
}
if (word.match(/o$/)) {
return word + "es";
}
return word + "s";
}
// src/generators/utils/parser.ts
function parseFields(fields = []) {
return fields.map((field) => {
const [name, type] = field.split(":");
if (!name || !type) {
throw new Error(`Format field tidak valid: ${field}`);
}
const validTypes = ["string", "number", "boolean", "date", "text", "json", "enum"];
if (!validTypes.includes(type)) {
throw new Error(`Tipe data ${source_default.red(type)} tidak valid! Pilih dari: ${validTypes.join(", ")}`);
}
return { name, type };
});
}
// src/generators/languages/typescript/constants/index.ts
var exports_constants = {};
__export(exports_constants, {
nextStructure: () => nextStructure,
kontasStructure: () => kontasStructure,
honoStructure: () => honoStructure,
expressStructure: () => expressStructure,
elysiaStructure: () => elysiaStructure
});
// src/generators/languages/typescript/constants/structures/express.ts
var expressStructure = {
getModulesPath: (projectDir) => `${projectDir}/modules`.replace(/\/+/g, "/"),
getRoutersPath: (projectDir) => `${projectDir}/routers`.replace(/\/+/g, "/")
};
// src/generators/languages/typescript/constants/structures/elysia.ts
var elysiaStructure = {
getModulesPath: (projectDir) => `${projectDir}/modules`.replace(/\/+/g, "/"),
getRoutersPath: (projectDir) => `${projectDir}/routers`.replace(/\/+/g, "/")
};
// src/generators/languages/typescript/constants/structures/hono.ts
var honoStructure = {
getModulesPath: (projectDir) => `${projectDir}/modules`.replace(/\/+/g, "/"),
getRoutersPath: (projectDir) => `${projectDir}/routers`.replace(/\/+/g, "/")
};
// src/generators/languages/typescript/constants/structures/next.ts
var nextStructure = {
getModulesPath: (projectDir) => `${projectDir}/modules`.replace(/\/+/g, "/"),
getRoutersPath: (projectDir) => `${projectDir}/app/api`.replace(/\/+/g, "/")
};
// src/generators/languages/typescript/constants/structures/kontas.ts
var kontasStructure = {
getModulesPath: (projectDir) => `${projectDir}/modules`.replace(/\/+/g, "/")
};
// src/generators/utils/json.template.ts
var generateJSONData = (name, fields, count = 10) => {
const generateRandomValue = (type) => {
switch (type) {
case "string":
const words = ["Henotic Labs", "Koding Fantasi", "Television", "Pemanasan Kaki"];
return words[Math.floor(Math.random() * words.length)];
case "number":
return Math.floor(Math.random() * 1000);
case "boolean":
return Math.random() > 0.5;
case "date":
const start = new Date(2020, 1, 1);
const end = new Date;
return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime())).toISOString();
default:
return null;
}
};
const sampleData = Array.from({ length: count }, () => {
const item = {
...Object.fromEntries(fields.map((field) => [
field.name,
generateRandomValue(field.type)
]))
};
return item;
});
return JSON.stringify(sampleData, null, 4);
};
// src/generators/languages/typescript/templates/framework/express/router.ts
var generateRouter = (name, pluralName) => `import { Router } from "express"
import { ${pluralName.toLowerCase()} } from "./modules/${pluralName.toLowerCase()}"
const router = Router()
.use('/${pluralName.toLowerCase()}', ${pluralName.toLowerCase()})
export { router }`;
// src/generators/languages/typescript/templates/framework/elysia/router.ts
var generateRouter2 = (name, pluralName) => `import { Elysia } from 'elysia'
import { ${name} } from './modules/${pluralName.toLowerCase()}'
export const router = (app: Elysia) => {
return app
.group('/api', app => app
.use(${name})
)
}`;
// src/generators/languages/typescript/templates/framework/hono/router.ts
var generateRouter3 = (name, pluralName) => `import { Hono } from "hono"
import { ${pluralName.toLowerCase()} } from "./modules/${pluralName.toLowerCase()}"
const router = new Hono()
.route('/${pluralName.toLowerCase()}', ${pluralName.toLowerCase()})
export { router }`;
// src/generators/languages/typescript/src/router.ts
async function updateRouter(name, framework, projectDir = "") {
if (framework === "next") {
console.log(source_default.yellow("\u26A0\uFE0F Skip generate router.ts (Next.js menggunakan App Router)"));
return;
}
const cwd = process.cwd();
const routerPath = `${cwd}/${projectDir ? projectDir + "/" : ""}router.ts`;
const pluralName = pluralize(name);
let content = "";
try {
content = await Bun.file(routerPath).text();
} catch (error) {
const generators = {
express: generateRouter,
elysia: generateRouter2,
hono: generateRouter3
};
content = generators[framework](name, pluralName);
await Bun.write(routerPath, content);
return;
}
const imports = content.split(`
`)[0];
let newImport = "";
if (framework === "elysia") {
newImport = `import { ${name} } from './modules/${pluralName.toLowerCase()}'`;
} else {
newImport = `import { ${pluralName.toLowerCase()} } from "./modules/${pluralName.toLowerCase()}"`;
}
const lines = content.split(`
`);
const routes = lines.filter((line) => {
if (framework === "elysia") {
return line.includes(`.use(${name})`);
} else if (framework === "express") {
return line.includes(`.use('/${pluralName.toLowerCase()}', ${pluralName.toLowerCase()})`);
} else {
return line.includes(`.route('/${pluralName.toLowerCase()}', ${pluralName.toLowerCase()})`);
}
});
if (routes.length > 0) {
console.log(source_default.yellow(`\u26A0\uFE0F Route untuk ${name} sudah ada, skip update router...`));
return;
}
if (!imports.includes(newImport)) {
content = content.replace(imports, `${imports}
${newImport}`);
}
const routePatterns = {
express: {
search: "const router = Router()",
replace: (name2, plural) => `const router = Router()
.use('/${plural.toLowerCase()}', ${plural.toLowerCase()})`
},
elysia: {
search: "app => app",
replace: (name2) => `app => app
.use(${name2})`
},
hono: {
search: "const router = new Hono()",
replace: (name2, plural) => `const router = new Hono()
.route('/${plural.toLowerCase()}', ${plural.toLowerCase()})`
}
};
const pattern = routePatterns[framework];
const hasExistingRoutes = framework === "elysia" ? content.includes(".use(") : content.includes(framework === "express" ? ".use(" : ".route(");
if (hasExistingRoutes) {
const lastChainIndex = content.lastIndexOf(framework === "express" ? ".use(" : framework === "elysia" ? ".use(" : ".route(");
const beforeChain = content.slice(0, lastChainIndex);
const afterChain = content.slice(lastChainIndex);
if (framework === "elysia") {
content = `${beforeChain}
.use(${name})${afterChain}`;
} else {
content = `${beforeChain}
.${framework === "express" ? "use" : "route"}('/${pluralName.toLowerCase()}', ${pluralName.toLowerCase()})${afterChain}`;
}
} else {
content = content.replace(pattern.search, pattern.replace(name, pluralName));
}
await Bun.write(routerPath, content);
}
// src/generators/languages/typescript/templates/framework/express/repository/mariadb.ts
var generateMariadbRepository = (name, pluralName) => `import { db } from "../../config";
import type { Create${name}, Update${name}, ${pluralName}, ${name}Id } from "./${name.toLowerCase()}.schema";
import { ${name} } from "./${name.toLowerCase()}.schema";
export type Result<T> = {
success: boolean;
message?: string;
data: T | null;
error?: unknown;
};
export class ${name}Repository {
private readonly table = "${pluralName.toLowerCase()}";
create = async (data: Create${name}): Promise<Result<${pluralName}>> => {
try {
const fields = Object.keys(data);
const values = Object.values(data);
const placeholders = values.map(() => '?').join(', ');
const result = await db.query(\`
INSERT INTO \${this.table}
(\${fields.join(', ')}, createdAt, updatedAt)
VALUES (\${placeholders}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
\`, values);
const newItem = await db.query(\`
SELECT *
FROM \${this.table}
WHERE id = ?
\`, [result.insertId]);
if (!newItem?.[0]) {
throw new Error("Failed to create ${name.toLowerCase()}");
}
return {
success: true,
message: "${name} created successfully",
data: new ${name}(newItem[0]) as ${pluralName}
};
} catch (error) {
console.error('Error in create:', error);
throw new Error(error instanceof Error ? error.message : "Failed to create ${name.toLowerCase()}");
}
};
findAll = async (): Promise<Result<${pluralName}[]>> => {
try {
const rows = await db.query(\`
SELECT *
FROM \${this.table}
\`);
return {
success: true,
data: rows.map((row: ${pluralName}) => new ${name}(row) as ${pluralName})
};
} catch (error) {
console.error('Error in findAll:', error);
throw new Error("Failed to fetch ${pluralName.toLowerCase()}");
}
};
findById = async ({ id }: ${name}Id): Promise<Result<${pluralName}>> => {
try {
const row = await db.query(\`
SELECT *
FROM \${this.table}
WHERE id = ?
\`, [id]);
if (!row?.[0]) {
throw new Error("${name} not found");
}
return {
success: true,
data: new ${name}(row[0]) as ${pluralName}
};
} catch (error) {
console.error('Error in findById:', error);
throw new Error(error instanceof Error ? error.message : "Failed to find ${name.toLowerCase()}");
}
};
update = async ({ id }: ${name}Id, data: Update${name}): Promise<Result<${pluralName}>> => {
try {
const fields = Object.keys(data);
const values = Object.values(data);
const setClause = fields
.map(field => \`\${field} = ?\`)
.join(', ');
await db.query(\`
UPDATE \${this.table}
SET \${setClause}, updatedAt = CURRENT_TIMESTAMP
WHERE id = ?
\`, [...values, id]);
const row = await db.query(\`
SELECT *
FROM \${this.table}
WHERE id = ?
\`, [id]);
if (!row?.[0]) {
throw new Error("${name} not found");
}
return {
success: true,
message: "${name} updated successfully",
data: new ${name}(row[0]) as ${pluralName}
};
} catch (error) {
console.error('Error in update:', error);
throw new Error(error instanceof Error ? error.message : "Failed to update ${name.toLowerCase()}");
}
};
delete = async ({ id }: ${name}Id): Promise<Result<${pluralName}>> => {
try {
const row = await db.query(\`
SELECT *
FROM \${this.table}
WHERE id = ?
\`, [id]);
if (!row?.[0]) {
throw new Error("${name} not found");
}
await db.query(\`
DELETE FROM \${this.table}
WHERE id = ?
\`, [id]);
return {
success: true,
message: "${name} deleted successfully",
data: new ${name}(row[0]) as ${pluralName}
};
} catch (error) {
console.error('Error in delete:', error);
throw new Error(error instanceof Error ? error.message : "Failed to delete ${name.toLowerCase()}");
}
};
}
// ! -- CUSTOM METHODS --
// You can add custom methods or business logic below this line
// For example:
// export class Custom${name}Repository extends ${name}Repository {
// customMethod = async () => {
// // Your custom logic here
// }
// }
export const Repository = new ${name}Repository()`;
// src/generators/languages/typescript/templates/framework/express/repository/postgresql.ts
var generatePostgresRepository = (name, pluralName) => `import { sql } from "../../config";
import type { Create${name}, Update${name}, ${pluralName}, ${name}Id } from "./${name.toLowerCase()}.schema";
import { ${name} } from "./${name.toLowerCase()}.schema";
export class ${name}Repository {
private readonly table = "${pluralName.toLowerCase()}";
create = async (data: Create${name}) => {
try {
const [result] = await sql\`
INSERT INTO \${sql(this.table)} \${sql(data)}
RETURNING *
\`;
return {
success: true,
message: "${name} created successfully",
data: new ${name}(result) as ${pluralName}
};
} catch (error) {
console.error("Error creating ${name.toLowerCase()}:", error);
throw error;
}
};
findAll = async () => {
try {
const result = await sql\`SELECT * FROM \${sql(this.table)}\`;
return {
success: true,
data: result.map((row: ${pluralName}) => new ${name}(row) as ${pluralName})
};
} catch (error) {
console.error("Error finding all ${pluralName.toLowerCase()}:", error);
throw error;
}
};
findById = async ({ id }: ${name}Id) => {
try {
const [result] = await sql\`SELECT * FROM \${sql(this.table)} WHERE "id" = \${id}\`;
if (!result) {
throw new Error(\`${name} with id \${id} not found\`);
}
return {
success: true,
data: new ${name}(result) as ${pluralName}
};
} catch (error) {
console.error("Error finding ${name.toLowerCase()} by id:", error);
throw error;
}
};
update = async ({ id }: ${name}Id, data: Update${name}) => {
try {
const [result] = await sql\`
UPDATE \${sql(this.table)}
SET \${sql(data)}, "updatedAt" = NOW()
WHERE "id" = \${id}
RETURNING *
\`;
if (!result) {
throw new Error(\`${name} with id \${id} not found\`);
}
return {
success: true,
message: "${name} updated successfully",
data: new ${name}(result) as ${pluralName}
};
} catch (error) {
console.error("Error updating ${name.toLowerCase()}:", error);
throw error;
}
};
delete = async ({ id }: ${name}Id) => {
try {
return await sql.begin(async (tx) => {
const [${name.toLowerCase()}] = await tx\`SELECT * FROM \${sql(this.table)} WHERE "id" = \${id}\`;
if (!${name.toLowerCase()}) {
throw new Error(\`${name} with id \${id} not found\`);
}
await tx\`DELETE FROM \${sql(this.table)} WHERE "id" = \${id}\`;
return {
success: true,
message: "${name} deleted successfully",
data: new ${name}(${name.toLowerCase()}) as ${pluralName}
};
});
} catch (error) {
console.error("Error deleting ${name.toLowerCase()}:", error);
throw error;
}
};
}
export const Repository = new ${name}Repository();`;
// src/generators/languages/typescript/templates/framework/express/repository/sqlite.ts
var generateSqliteRepository = (name, pluralName) => `import { db } from "../../config";
import type { Create${name}, Update${name}, ${pluralName}, ${name}Id } from "./${name.toLowerCase()}.schema";
import { ${name} } from "./${name.toLowerCase()}.schema";
// Tipe untuk data dari SQLite (timestamps sebagai string)
type SQLite${name} = Omit<${pluralName}, 'createdAt' | 'updatedAt'> & {
createdAt: string;
updatedAt: string;
};
export class ${name}Repository {
private readonly table = "${pluralName.toLowerCase()}";
private convertDates(${name.toLowerCase()}: SQLite${name}): ${pluralName} {
return new ${name}({
...${name.toLowerCase()},
createdAt: new Date(${name.toLowerCase()}.createdAt),
updatedAt: new Date(${name.toLowerCase()}.updatedAt)
}) as ${pluralName};
}
create = async (data: Create${name}) => {
try {
const fields = Object.keys(data);
const columns = fields.join(', ');
const placeholders = fields.map(f => \`$\${f}\`).join(', ');
const params = Object.fromEntries(fields.map(f => [\`$\${f}\`, data[f as keyof Create${name}]]));
const newItem = db.query(\`
INSERT INTO \${this.table}
(\${columns}, createdAt, updatedAt)
VALUES (\${placeholders}, datetime('now'), datetime('now'))
RETURNING *;
\`).get(params) as SQLite${name};
if (!newItem) throw new Error("Failed to create ${name.toLowerCase()}");
return {
success: true,
message: "${name} created successfully",
data: this.convertDates(newItem)
};
} catch (error) {
console.error("Error creating ${name.toLowerCase()}:", error);
throw error;
}
};
findAll = async () => {
try {
const query = db.query(\`SELECT * FROM \${this.table}\`);
const rows = query.all() as SQLite${name}[];
return {
success: true,
data: rows.map(this.convertDates)
};
} catch (error) {
console.error("Error finding all ${pluralName.toLowerCase()}:", error);
throw error;
}
};
findById = async ({ id }: ${name}Id) => {
try {
const query = db.query(\`
SELECT *
FROM \${this.table}
WHERE id = $id
\`);
const row = query.get({ $id: id }) as SQLite${name} | undefined;
if (!row) {
throw new Error(\`${name} with id \${id} not found\`);
}
return {
success: true,
data: this.convertDates(row)
};
} catch (error) {
console.error("Error finding ${name.toLowerCase()} by id:", error);
throw error;
}
};
update = async ({ id }: ${name}Id, data: Update${name}) => {
try {
const fields = Object.keys(data);
const setClause = fields.map(f => \`\${f} = $\${f}\`).join(', ');
const params = { $id: id, ...Object.fromEntries(fields.map(f => [\`$\${f}\`, data[f as keyof Update${name}]])) };
db.query(\`
UPDATE \${this.table}
SET \${setClause}, updatedAt = datetime('now')
WHERE id = $id
\`).run(params);
const row = db.query(\`SELECT * FROM \${this.table} WHERE id = $id\`)
.get({ $id: id }) as SQLite${name};
if (!row) throw new Error(\`${name} with id \${id} not found\`);
return {
success: true,
message: "${name} updated successfully",
data: this.convertDates(row)
};
} catch (error) {
console.error("Error updating ${name.toLowerCase()}:", error);
throw error;
}
};
delete = async ({ id }: ${name}Id) => {
try {
const findQuery = db.query(\`
SELECT *
FROM \${this.table}
WHERE id = $id
\`);
const row = findQuery.get({ $id: id }) as SQLite${name} | undefined;
if (!row) {
throw new Error(\`${name} with id \${id} not found\`);
}
const deleteQuery = db.query(\`DELETE FROM \${this.table} WHERE id = $id\`);
deleteQuery.run({ $id: id });
return {
success: true,
message: "${name} deleted successfully",
data: this.convertDates(row)
};
} catch (error) {
console.error("Error deleting ${name.toLowerCase()}:", error);
throw error;
}
};
}
// ! -- CUSTOM METHODS --
// You can add custom methods or business logic below this line
// For example:
// export class Custom${name}Repository extends ${name}Repository {
// customMethod = async () => {
// // Your custom logic here
// }
// }
export const Repository = new ${name}Repository()`;
// src/generators/languages/typescript/templates/framework/express/repository/mongodb.ts
var generateMongoRepository = (name, pluralName) => `import { ObjectId } from "mongodb";
import { db } from "../../config";
import type { Create${name}, Update${name}, ${pluralName}, ${name}Id } from "./${name.toLowerCase()}.schema";
import { ${name} } from "./${name.toLowerCase()}.schema";
export class ${name}Repository {
private readonly collection = "${pluralName.toLowerCase()}";
private getCollection = async () => {
return db.collection(this.collection);
};
create = async (data: Create${name}) => {
try {
const doc = {
...data,
createdAt: new Date(),
updatedAt: new Date()
};
const collection = await this.getCollection();
const result = await collection.insertOne(doc);
if (!result.acknowledged) {
throw new Error("Failed to create ${name.toLowerCase()}");
}
return {
success: true,
message: "${name} created successfully",
data: new ${name}({ ...doc, _id: result.insertedId }) as ${pluralName}
};
} catch (error) {
console.error("Error creating ${name.toLowerCase()}:", error);
throw error;
}
};
findAll = async () => {
try {
const collection = await this.getCollection();
const docs = await collection
.find({})
.sort({ _id: -1 })
.toArray() as ${pluralName}[];
return {
success: true,
data: docs.map(doc => new ${name}(doc) as ${pluralName})
};
} catch (error) {
console.error("Error finding all ${pluralName.toLowerCase()}:", error);
throw error;
}
};
findById = async ({ id }: ${name}Id) => {
try {
const collection = await this.getCollection();
const doc = await collection
.findOne({ _id: new ObjectId(id) }) as ${pluralName} | null;
if (!doc) {
throw new Error(\`${name} with id \${id} not found\`);
}
return {
success: true,
data: new ${name}(doc) as ${pluralName}
};
} catch (error) {
console.error("Error finding ${name.toLowerCase()} by id:", error);
throw error;
}
};
update = async ({ id }: ${name}Id, data: Update${name}) => {
try {
const collection = await this.getCollection();
const result = await collection
.findOneAndUpdate(
{ _id: new ObjectId(id) },
{
$set: {
...data,
updatedAt: new Date()
}
},
{ returnDocument: 'after' }
);
if (!result) {
throw new Error(\`${name} with id \${id} not found\`);
}
return {
success: true,
message: "${name} updated successfully",
data: new ${name}(result) as ${pluralName}
};
} catch (error) {
console.error("Error updating ${name.toLowerCase()}:", error);
throw error;
}
};
delete = async ({ id }: ${name}Id) => {
try {
const collection = await this.getCollection();
const doc = await collection
.findOne({ _id: new ObjectId(id) });
if (!doc) {
throw new Error(\`${name} with id \${id} not found\`);
}
await collection.deleteOne({ _id: new ObjectId(id) });
return {
success: true,
message: "${name} deleted successfully",
data: new ${name}(doc) as ${pluralName}
};
} catch (error) {
console.error("Error deleting ${name.toLowerCase()}:", error);
throw error;
}
};
}
// ! -- CUSTOM METHODS --
// You can add custom methods or business logic below this line
// For example:
// export class Custom${name}Repository extends ${name}Repository {
// customMethod = async () => {
// // Your custom logic here
// }
// }
export const Repository = new ${name}Repository();`;
// src/generators/languages/typescript/templates/framework/express/schema/mongoose.ts
var generateMongooseSchema = (name, fields) => {
const mapTypeToMongoose = (zodType) => {
const typeMap = {
string: "String",
number: "Number",
boolean: "Boolean",
date: "Date",
array: "Array",
object: "Object"
};
return typeMap[zodType] || "String";
};
return `import { z } from "zod";
import mongoose from "mongoose";
// Definisi schema mongoose
const ${name.toLowerCase()}Schema = new mongoose.Schema({
${fields.map((f) => `${f.name}: {
type: ${mapTypeToMongoose(f.type)},
required: true
}`).join(`,
`)}
}, {
timestamps: true
});
// Model mongoose
export const ${name} = mongoose.model('${name}', ${name.toLowerCase()}Schema);
// Zod schema untuk validasi
const ${name}Schema = z.object({
${fields.map((f) => `${f.name}: z.${f.type}()`).join(`,
`)}
})
const TimestampSchema = z.object({
createdAt: z.date(),
updatedAt: z.date()
})
export const ${name}IdValidate = z.object({
id: z.string().refine((val) => mongoose.Types.ObjectId.isValid(val), {
message: "ID harus berupa ObjectId yang valid"
})
})
export const Create${name}Validate = ${name}Schema
export const ${pluralize(name)}Validate = ${name}Schema
.merge(z.object({
_id: z.instanceof(mongoose.Types.ObjectId).or(z.string())
}))
.merge(TimestampSchema)
export const Update${name}Validate = ${name}Schema.partial()
export type Create${name} = z.infer<typeof Create${name}Validate>
export type ${pluralize(name)} = z.infer<typeof ${pluralize(name)}Validate>
export type Update${name} = z.infer<typeof Update${name}Validate>
export type ${name}Id = z.infer<typeof ${name}IdValidate>
`;
};
// src/generators/languages/typescript/templates/framework/express/schema/mongodb.ts
var generateMongodbSchema = (name, fields) => `import { z } from "zod"
import { ObjectId } from "mongodb"
export class ${name} {
constructor(data: Partial<${pluralize(name)}>) {
Object.assign(this, data)
}
}
const ${name}Schema = z.object({
${fields.map((f) => `${f.name}: z.${f.type}()`).join(`,
`)}
})
const WithIdSchema = z.object({
_id: z.instanceof(ObjectId)
})
const TimestampSchema = z.object({
createdAt: z.date(),
updatedAt: z.date()
})
export const ${name}IdValidate = z.object({
id: z.string().regex(/^[0-9a-fA-F]{24}$/, "Invalid ObjectId format")
})
export const Create${name}Validate = ${name}Schema
export const ${pluralize(name)}Validate = ${name}Schema
.merge(WithIdSchema)
.merge(TimestampSchema)
export const Update${name}Validate = ${name}Schema.partial()
export type Create${name} = z.infer<typeof Create${name}Validate>
export type ${pluralize(name)} = z.infer<typeof ${pluralize(name)}Validate>
export type Update${name} = z.infer<typeof Update${name}Validate>
export type ${name}Id = z.infer<typeof ${name}IdValidate>
`;
// src/generators/languages/typescript/templates/framework/express/schema/sql.ts
var generateSqlSchema = (name, fields) => `import { z } from "zod"
export class ${name} {
constructor(data: Partial<${pluralize(name)}>) {
Object.assign(this, data)
}
}
const ${name}Schema = z.object({
${fields.map((f) => `${f.name}: z.${f.type}()`).join(`,
`)}
})
const WithIdSchema = z.object({
id: z.number()
})
const TimestampSchema = z.object({
createdAt: z.date(),
updatedAt: z.date()
})
export const ${name}IdValidate = z.object({
id: z.coerce.number().positive("ID harus positif")
})
export const Create${name}Validate = ${name}Schema
export const ${pluralize(name)}Validate = ${name}Schema
.merge(WithIdSchema)
.merge(TimestampSchema)
export const Update${name}Validate = ${name}Schema.partial()
export type Create${name} = z.infer<typeof Create${name}Validate>
export type ${pluralize(name)} = z.infer<typeof ${pluralize(name)}Validate>
export type Update${name} = z.infer<typeof Update${name}Validate>
export type ${name}Id = z.infer<typeof ${name}IdValidate>
`;
// src/generators/languages/typescript/templates/framework/express/service/mongoose.ts
var generateMongooseService = (name, pluralName) => `import { db } from '../../config';
import type { Create${name}, Update${name}, ${pluralName} } from './${name.toLowerCase()}.schema';
import { ${name}, Create${name}Validate, Update${name}Validate } from './${name.toLowerCase()}.schema';
export type Result<T> = {
success: boolean;
message?: string;
data: T | null;
};
export class ${name}Service {
create = async (data: Create${name}): Promise<Result<${pluralName}>> => {
try {
const validatedData = Create${name}Validate.parse(data);
const ${name.toLowerCase()} = new ${name}(validatedData);
const saved${name} = await ${name.toLowerCase()}.save();
return {
success: true,
message: "${name} created successfully",
data: saved${name}
};
} catch (error) {
console.error("Error creating ${name.toLowerCase()}:", error);
throw error;
}
};
getAll = async (): Promise<Result<${pluralName}[]>> => {
try {
const ${pluralName.toLowerCase()} = await ${name}.find();
return {
success: true,
data: ${pluralName.toLowerCase()}
};
} catch (error) {
console.error("Error getting all ${pluralName.toLowerCase()}:", error);
throw error;
}
};
getById = async (id: string): Promise<Result<${pluralName}>> => {
try {
if (!db.Types.ObjectId.isValid(id)) {
throw new Error("Invalid ${name.toLowerCase()} ID");
}
const ${name.toLowerCase()} = await ${name}.findById(id);
if (!${name.toLowerCase()}) {
throw new Error("${name} not found");
}
return {
success: true,
data: ${name.toLowerCase()}
};
} catch (error) {
console.error(\`Error getting ${name.toLowerCase()} with ID \${id}:\`, error);
throw error;
}
};
update = async (id: string, data: Update${name}): Promise<Result<${pluralName}>> => {
try {
if (!db.Types.ObjectId.isValid(id)) {
throw new Error("Invalid ${name.toLowerCase()} ID");
}
// Validasi data dengan Zod
const validatedData = Update${name}Validate.parse(data);
const updated${name} = await ${name}.findByIdAndUpdate(
id,
{ ...validatedData },
{ new: true }
);
if (!updated${name}) {
throw new Error("${name} not found");
}
return {
success: true,
message: "${name} updated successfully",
data: updated${name}
};
} catch (error) {
console.error(\`Error updating ${name.toLowerCase()} with ID \${id}:\`, error);
throw error;
}
};
delete = async (id: string): Promise<Result<${pluralName}>> => {
try {
if (!db.Types.ObjectId.isValid(id)) {
throw new Error("Invalid ${name.toLowerCase()} ID");
}
const deleted${name} = await ${name}.findByIdAndDelete(id);
if (!deleted${name}) {
throw new Error("${name} not found");
}
return {
success: true,
message: "${name} deleted successfully",
data: deleted${name}
};
} catch (error) {
console.error(\`Error deleting ${name.toLowerCase()} with ID \${id}:\`, error);
throw error;
}
};
}
export const Service = new ${name}Service();
`;
// src/generators/languages/typescript/templates/framework/express/service/mongodb.ts
var generateMongodbService = (name, pluralName) => `import { Repository as ${name} } from "./${name.toLowerCase()}.repository";
import type { Create${name}, Update${name} } from "./${name.toLowerCase()}.schema";
import {
Create${name}Validate,
Update${name}Validate,
${name}IdValidate
} from "./${name.toLowerCase()}.schema";
export const Service = {
create: async (data: Create${name}) => {
try {
const validated = Create${name}Validate.parse(data);
return await ${name}.create(validated);
} catch (error) {
console.error("Service error creating ${name.toLowerCase()}:", error);
throw error;
}
},
getAll: async () => {
try {
return await ${name}.findAll();
} catch (error) {
console.error("Service error getting all ${pluralName.toLowerCase()}:", error);
throw error;
}
},
getById: async (id: string) => {
try {
const { id: validId } = ${name}IdValidate.parse({ id });
return await ${name}.findById({ id: validId });
} catch (error) {
console.error("Service error getting ${name.toLowerCase()} by id:", error);
throw error;
}
},
update: async (id: string, data: Update${name}) => {
try {
const { id: validId } = ${name}IdValidate.parse({ id });
const validated = Update${name}Validate.parse(data);
return await ${name}.update({ id: validId }, validated);
} catch (error) {
console.error("Service error updating ${name.toLowerCase()}:", error);
throw error;
}
},
delete: async (id: string) => {
try {
const { id: validId } = ${name}IdValidate.parse({ id });
return await ${name}.delete({ id: validId });
} catch (error) {
console.error("Service error deleting ${name.toLowerCase()}:", error);
throw error;
}
}
};`;
// src/generators/languages/typescript/templates/framework/express/service/sql.ts
var generateSqlService = (name, pluralName) => `import { Repository as ${name} } from "./${name.toLowerCase()}.repository";
import type { Create${name}, Update${name} } from "./${name.toLowerCase()}.schema";
import {
Create${name}Validate,
Update${name}Validate,
${name}IdValidate
} from "./${name.toLowerCase()}.schema";
export const Service = {
create: async (data: Create${name}) => {
try {
const validated = Create${name}Validate.parse(data);
return await ${name}.create(validated);
} catch (error) {
console.error("Service error creating ${name.toLowerCase()}:", error);
throw error;
}
},
getAll: async () => {
try {
return await ${name}.findAll();
} catch (error) {
console.error("Service error getting all ${pluralName.toLowerCase()}:", error);
throw error;
}
},
getById: async (id: string) => {
try {
const { id: validId } = ${name}IdValidate.parse({ id: Number(id) });
return await ${name}.findById({ id: validId });
} catch (error) {
console.error("Service error getting ${name.toLowerCase()} by id:", error);
throw error;
}
},
update: async (id: string, data: Update${name}) => {
try {
const { id: validId } = ${name}IdValidate.parse({ id: Number(id) });
const validated = Update${name}Validate.parse(data);
return await ${name}.update({ id: validId }, validated);
} catch (error) {
console.error("Service error updating ${name.toLowerCase()}:", error);
throw error;
}
},
delete: async (id: string) => {
try {
const { id: validId } = ${name}IdValidate.parse({ id: Number(id) });
return await ${name}.delete({ id: validId });
} catch (error) {
console.error("Service error deleting ${name.toLowerCase()}:", error);
throw error;
}
}
};`;
// src/generators/languages/typescript/templates/framework/express/controller.ts
var generateController = (name, pluralName) => `import { Router } from "express";
import { Service as ${name} } from "./${name.toLowerCase()}.service";
export const ${pluralName.toLowerCase()} = Router()
.post("/", async (req, res, next) => {
try {
const result = await ${name}.create(req.body);
res.status(201).json(result);
} catch (error) {
next(error);
}
})
.get("/", async (_req, res, next) => {
try {
const result = await ${name}.getAll();
res.status(200).json(result);
} catch (error) {
next(error);
}
})
.get("/:id", async (req, res, next) => {
try {
const { id } = req.params;
const result = await ${name}.getById(id);
res.status(200).json(result);
} catch (error) {
next(error);
}
})
.put("/:id", async (req, res, next) => {
try {
const { id } = req.params;
const result = await ${name}.update(id, req.body);
res.status(200).json(result);
} catch (error) {
next(error);
}
})
.delete("/:id", async (req, res, next) => {
try {
const { id } = req.params;
const result = await ${name}.delete(id);
res.status(200).json(result);
} catch (error) {
next(error);
}
});`;
// src/generators/languages/typescript/templates/framework/express/server.ts
var generateServer = () => `import express from "express";
import cors from "cors";
import { router } from "./router";
import { errorHandler } from "./error";
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());
app.use('/api', router);
app.use(errorHandler);
app.listen(3000, () => {
console.log("Server is running on port 3000 \uD83D\uDE80");
});
export default app;`;
// src/generators/languages/typescript/templates/framework/express/error.ts
var generateError = () => `import type { Request, Response, NextFunction, ErrorRequestHandler } from "express";
import { ZodError } from "zod";
type ErrorResult = {
success: boolean;
message?: string;
data: null;
errors?: {
field: string;
message: string;
}[];
};
type HttpStatus =
| 400 // Bad Request
| 401 // Unauthorized
| 403 // Forbidden
| 404 // Not Found
| 405 // Method Not Allowed
| 408 // Request Timeout
| 409 // Conflict
| 422 // Unprocessable Entity
| 429 // Too Many Requests
| 500 // Internal Server Error
| 502 // Bad Gateway
| 503 // Service Unavailable
| 504 // Gateway Timeout
export const errorHandler: ErrorRequestHandler = (
error: Error | ZodError,
_req: Request,
res: Response,
_next: NextFunction
): void => {
console.error("Error:", error);
let status: HttpStatus = 500;
let response: ErrorResult = {
success: false,
message: "Terjadi kesalahan internal server",
data: null
};
// Handle specific errors (400, 404, etc)
if (error instanceof ZodError) {
status = 400;
response = {
success: false,
message: "Data tidak valid",
data: null,
errors: error.errors.map(e => ({
field: e.path.join('.'),
message: e.message
}))
};
} else if (error.message.toLowerCase().includes('not found')) {
status = 404;
response = {
success: false,
message: error.message,
data: null
};
} else if (error.message.toLowerCase().includes('invalid') || error.message.toLowerCase().includes('failed')) {
status = 400;
response = {
success: false,
message: error.message,
data: null
};
} else if (error.message.toLowerCase().includes('unauthorized')) {
status = 401;
response = {
success: false,
message: error.message,
data: null
};
} else if (error.message.toLowerCase().includes('forbidden')) {
status = 403;
response = {
success: false,
message: error.message,
data: null
};
}
res.status(status).json(response);
}
`;
// src/generators/languages/typescript/templates/framework/elysia/repository/mariadb.ts
var generateMariadbRepository2 = (name, pluralName) => `import { db } from "../../config";
import type { Create${name}, Update${name}, ${pluralName}, ${name}Id } from "./${name.toLowerCase()}.schema";
export type Result<T> = {
success: boolean;
message?: string;
data: T | null;
error?: unknown;
};
export class ${name}Repository {
private readonly table = "${pluralName.toLowerCase()}";
create = async (data: Create${name}): Promise<Result<${pluralName}>> => {
try {
const fields = Object.keys(data);
const values = Object.values(data);
const placeholders = values.map(() => '?').join(', ');
const result = await db.query(\`
INSERT INTO \${this.table}
(\${fields.join(', ')}, createdAt, updatedAt)
VALUES (\${placeholders}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
\`, values);
const newItem = await db.query(\`
SELECT *
FROM \${this.table}
WHERE id = ?
\`, [result.insertId]);
if (!newItem?.[0]) {
throw new Error("Failed to create ${name.toLowerCase()}");
}
return {
success: true,
message: "${name} created successfully",
data: newItem[0]
};
} catch (error) {
console.error('Error in create:', error);
throw new Error(error instanceof Error ? error.message : "Failed to create ${name.toLowerCase()}");
}
};
findAll = async (): Promise<Result<${pluralName}[]>> => {
try {
const rows = await db.query(\`
SELECT *
FROM \${this.table}
\`);
return {
success: true,
data: rows
};
} catch (error) {
console.error('Error in findAll:', error);
throw new Error("Failed to fetch ${pluralName.toLowerCase()}");
}
};
findById = async ({ id }: ${name}Id): Promise<Result<${pluralName}>> => {
try {
const row = await db.query(\`
SELECT *
FROM \${this.table}
WHERE id = ?
\`, [id]);
if (!row?.[0]) {
throw new Error("${name} not found");
}
return {
success: true,
data: row[0]
};
} catch (error) {
console.error('Error in findById:', error);
throw new Error(error instanceof Error ? error.message : "Failed to find ${name.toLowerCase()}");
}
};
update = async ({ id }: ${name}Id, data: Update${name}): Promise<Result<${pluralName}>> => {
try {
const fields = Object.keys(data);
const values = Object.values(data);
const setClause = fields
.map(field => \`\${field} = ?\`)
.join(', ');
await db.query(\`
UPDATE \${this.table}
SET \${setClause}, updatedAt = CURRENT_TIMESTAMP
WHERE id = ?
\`, [...values, id]);
const row = await db.query(\`
SELECT *
FROM \${this.table}
WHERE id = ?
\`, [id]);
if (!row?.[0]) {
throw new Error("${name} not found");
}
return {
success: true,
message: "${name} updated successfully",
data: row[0]
};
} catch (error) {
console.error('Error in update:', error);
throw new Error(error instanceof Error ? error.message : "Failed to update ${name.toLowerCase()}");
}
};
delete = async ({ id }: ${name}Id): Promise<Result<${pluralName}>> => {
try {
const row = await db.query(\`
SELECT *
FROM \${this.table}
WHERE id = ?
\`, [id]);
if (!row?.[0]) {
throw new Error("${name} not found");
}
await db.query(\`
DELETE FROM \${this.table}
WHERE id = ?
\`, [id]);
return {
success: true,
message: "${name} deleted successfully",
data: row[0]
};
} catch (error) {
console.error('Error in delete:', error);
throw new Error(error instanceof Error ? error.message : "Failed to delete ${name.toLowerCase()}");
}
};
}
// ! -- CUSTOM METHODS --
// You can add custom methods or business logic below this line
// For example:
// export class Custom${name}Repository extends ${name}Repository {
// customMethod = async () => {
// // Your custom logic here
// }
// }
export const Repository = new ${name}Repository();`;
// src/generators/languages/typescript/templates/framework/elysia/repository/postgresql.ts
var generatePostgresRepository2 = (name, pluralName) => `import { sql } from "../../config";
import type { Create${name}, Update${name}, ${pluralName}, ${name}Id } from "./${name.toLowerCase()}.schema";
import { NotFoundError, DatabaseError } from "../../error";
export class ${name}Repository {
private readonly table = "${pluralName.toLowerCase()}";
create = async (data: Create${name}) => {
try {
const [result] = await sql\`
INSERT INTO \${sql(this.table)} \${sql(data)}
RETURNING *
\`;
return {
success: true,
message: "${name} created successfully",
data: result as ${pluralName}
};
} catch (error) {
console.error("Error creating ${name.toLowerCase()}:", error);
throw new DatabaseError("Gagal membuat ${name.toLowerCase()} baru");
}
};
findAll = async () => {
try {
const result = await sql\`SELECT * FROM \${sql(this.table)}\`;
return {
success: true,
data: result as ${pluralName}[]
};
} catch (error) {
console.error("Error finding all ${pluralName.toLowerCase()}:", error);
throw new DatabaseError("Gagal mengambil daftar ${pluralName.toLowerCase()}");
}
};
findById = async ({ id }: ${name}Id) => {
try {
const [result] = await sql\`SELECT * FROM \${sql(this.table)} WHERE "id" = \${id}\`;
if (!result) {
throw new NotFoundError("${name}", id);
}
return {
success: true,
data: result as ${pluralName}
};
} catch (error) {
if (error instanceof NotFoundError) {
throw error;
}
console.error("Error finding ${name.toLowerCase()} by id:", error);
throw new DatabaseError("Gagal mencari ${name.toLowerCase()}");
}
};
update = async ({ id }: ${name}Id, data: Update${name}) => {
try {
const [result] = await sql\`
UPDATE \${sql(this.table)}
SET \${sql(data)}, "updatedAt" = NOW()
WHERE "id" = \${id}
RETURNING *
\`;
if (!result) {
throw new NotFoundError("${name}", id);
}
return {
success: true,
message: "${name} updated successfully",
data: result as ${pluralName}
};
} catch (error) {
if (error instanceof NotFoundError) {
throw error;
}
console.error("Error updating ${name.toLowerCase()}:", error);
throw new DatabaseError("Gagal memperbarui ${name.toLowerCase()}");
}
};
delete = async ({ id }: ${name}Id) => {
try {
return await sql.begin(async (tx) => {
const [${name.toLowerCase()}] = await tx\`SELECT * FROM \${sql(this.table)} WHERE "id" = \${id}\`;
if (!${name.toLowerCase()}) {
throw new NotFoundError("${name}", id);
}
await tx\`DELETE FROM \${sql(this.table)} WHERE "id" = \${id}\`;
return {
success: true,
message: "${name} deleted successfully",
data: ${name.toLowerCase()} as ${pluralName}
};
});
} catch (error) {
if (error instanceof NotFoundError) {
throw error;
}
console.error("Error deleting ${name.toLowerCase()}:", error);
throw new DatabaseError("Gagal menghapus ${name.toLowerCase()}");
}
};
}
// ! -- CUSTOM METHODS --
// You can add custom methods or business logic below this line
// For example:
// export class Custom${name}Repository extends ${name}Repository {
// customMethod = async () => {
// // Your custom logic here
// }
// }
export const Repository = new ${name}Repository();`;
// src/generators/languages/typescript/templates/framework/elysia/repository/sqlite.ts
var generateSqliteRepository2 = (name, pluralName) => `import { db } from "../../config";
import type { Create${name}, Update${name}, ${pluralName}, ${name}Id } from "./${name.toLowerCase()}.schema";
export type Result<T> = {
success: boolean;
message?: string;
data: T | null;
error?: unknown;
};
// Tipe untuk data dari SQLite (timestamps sebagai string)
type SQLite${name} = Omit<${pluralName}, 'createdAt' | 'updatedAt'> & {
createdAt: string;
updatedAt: string;
};
export class ${name}Repository {
private readonly table = "${pluralName.toLowerCase()}";
create = async (data: Create${name}): Promise<Result<${pluralName}>> => {
try {
const fields = Object.keys(data);
const placeholders = fields.map(field => \`$\${field}\`).join(', ');
const query = db.query(\`
INSERT INTO \${this.table}
(\${fields.join(', ')}, createdAt, updatedAt)
VALUES (\${placeholders}, datetime('now'), datetime('now'))
RETURNING *;
\`);
const newItem = query.get(data) as SQLite${name};
if (!newItem) {
throw new Error("Failed to create ${name.toLowerCase()}");
}
return {
success: true,
message: "${name} created successfully",
data: {
...newItem,
createdAt: new Date(newItem.createdAt),
updatedAt: new Date(newItem.updatedAt)
} as ${pluralName}
};
} catch (error) {
console.error("Error creating ${name.toLowerCase()}:", error);
return {
success: false,
data: null,
error: error instanceof Error ? error.message : "Failed to create ${name.toLowerCase()}"
};
}
};
findAll = async (): Promise<Result<${pluralName}[]>> => {
try {
const query = db.query(\`
SELECT *
FROM \${this.table}
\`);
const rows = query.all() as SQLite${name}[];
return {
success: true,
data: rows.map(row => ({
...row,
createdAt: new Date(row.createdAt),
updatedAt: new Date(row.updatedAt)
})) as ${pluralName}[]
};
} catch (error) {
console.error("Error finding all ${pluralName.toLowerCase()}:", error);
return {
success: false,
data: null,
error: error instanceof Error ? error.message : "Failed to fetch ${pluralName.toLowerCase()}"
};
}
};
findById = async ({ id }: ${name}Id): Promise<Result<${pluralName}>> => {
try {
const query = db.query(\`
SELECT *
FROM \${this.table}
WHERE id = $id
\`);
const row = query.get({ $id: id }) as SQLite${name} | undefined;
if (!row) {
throw new Error("${name} not found");
}
return {
success: true,
data: {
...row,
createdAt: new Date(row.createdAt),
updatedAt: new Date(row.updatedAt)
} as ${pluralName}
};
} catch (error) {
console.error("Error finding ${name.toLowerCase()} by id:", error);
return {
success: false,
data: null,
error: error instanceof Error ? error.message : "Failed to find ${name.toLowerCase()}"
};
}
};
update = async ({ id }: ${name}Id, data: Update${name}): Promise<Result<${pluralName}>> => {
try {
const fields = Object.keys(data);
const setClause = fields
.map(field => \`\${field} = $\${field}\`)
.join(', ');
const updateQuery = db.query(\`
UPDATE \${this.table}
SET \${setClause}, updatedAt = datetime('now')
WHERE id = $id
\`);
updateQuery.run({ ...data, $id: id });
const findQuery = db.query(\`
SELECT *
FROM \${this.table}
WHERE id = $id
\`);
const row = findQuery.get({ $id: id }) as SQLite${name} | undefined;
if (!row) {
throw new Error("${name} not found");
}
return {
success: true,
message: "${name} updated successfully",
data: {
...row,
createdAt: new Date(row.createdAt),
updatedAt: new Date(row.updatedAt)
} as ${pluralName}
};
} catch (error) {
console.error("Error updating ${name.toLowerCase()}:", error);
return {
success: false,
data: null,
error: error instanceof Error ? error.message : "Failed to update ${name.toLowerCase()}"
};
}
};
delete = async ({ id }: ${name}Id): Promise<Result<${pluralName}>> => {
try {
const findQuery = db.query(\`
SELECT *
FROM \${this.table}
WHERE id = $id
\`);
const row = findQuery.get({ $id: id }) as SQLite${name} | undefined;
if (!row) {
throw new Error("${name} not found");
}
const deleteQuery = db.query(\`DELETE FROM \${this.table} WHERE id = $id\`);
deleteQuery.run({ $id: id });
return {
success: true,
message: "${name} deleted successfully",
data: {
...row,
createdAt: new Date(row.createdAt),
updatedAt: new Date(row.updatedAt)
} as ${pluralName}
};
} catch (error) {
console.error("Error deleting ${name.toLowerCase()}:", error);
return {
success: false,
data: null,
error: error instanceof Error ? error.message : "Failed to delete ${name.toLowerCase()}"
};
}
};
}
// ! -- CUSTOM METHODS --
// You can add custom methods or business logic below this line
// For example:
// export class Custom${name}Repository extends ${name}Repository {
// customMethod = async () => {
// // Your custom logic here
// }
// }
export const Repository = new ${name}Repository();`;
// src/generators/languages/typescript/templates/framework/elysia/repository/mongodb.ts
var generateMongoRepository2 = (name, pluralName) => `import { ObjectId } from "mongodb";
import { db } from "../../config";
import type { Create${name}, Update${name}, ${pluralName}, ${name}Id } from "./${name.toLowerCase()}.schema";
export type Result<T> = {
success: boolean;
message?: string;
data: T | null;
};
export class ${name}Repository {
private readonly collection = "${pluralName.toLowerCase()}";
private getCollection = async () => {
return db.collection(this.collection);
};
create = async (data: Create${name}): Promise<Result<${pluralName}>> => {
try {
const doc = {
...data,
createdAt: new Date(),
updatedAt: new Date()
} as const;
const collection = await this.getCollection();
const result = await collection.insertOne(doc);
if (!result.acknowledged) {
return {
success: false,
message: "Failed to create ${name.toLowerCase()}",
data: null
};
}
return {
success: true,
message: "${name} created successfully",
data: { ...doc, _id: result.insertedId } as ${pluralName}
};
} catch (error) {
return {
success: false,
message: error instanceof Error ? error.message : "Failed to create ${name.toLowerCase()}",
data: null
};
}
};
findAll = async (): Promise<Result<${pluralName}[]>> => {
try {
const collection = await this.getCollection();
const docs = await collection
.find({})
.sort({ _id: -1 })
.toArray() as ${pluralName}[];
return {
success: true,
data: docs as ${pluralName}[]
};
} catch (error) {
return {
success: false,
message: error instanceof Error ? error.message : "Failed to fetch ${pluralName.toLowerCase()}",
data: null
};
}
};
findById = async ({ id }: ${name}Id): Promise<Result<${pluralName}>> => {
try {
const collection = await this.getCollection();
const doc = await collection
.findOne({ _id: new ObjectId(id) }) as ${pluralName} | null;
if (!doc) {
return {
success: false,
message: "${name} not found",
data: null
};
}
return {
success: true,
data: doc as ${pluralName}
};
} catch (error) {
return {
success: false,
message: error instanceof Error ? error.message : "Failed to find ${name.toLowerCase()}",
data: null
};
}
};
update = async ({ id }: ${name}Id, data: Update${name}): Promise<Result<${pluralName}>> => {
try {
const collection = await this.getCollection();
const result = await collection
.findOneAndUpdate(
{ _id: new ObjectId(id) },
{
$set: {
...data,
updatedAt: new Date()
}
},
{ returnDocument: 'after' }
);
if (!result) {
return {
success: false,
message: "${name} not found",
data: null
};
}
return {
success: true,
message: "${name} updated successfully",
data: result as ${pluralName}
};
} catch (error) {
return {
success: false,
message: error instanceof Error ? error.message : "Failed to update ${name.toLowerCase()}",
data: null
};
}
};
delete = async ({ id }: ${name}Id): Promise<Result<${pluralName}>> => {
try {
const collection = await this.getCollection();
const doc = await collection
.findOne({ _id: new ObjectId(id) });
if (!doc) {
return {
success: false,
message: "${name} not found",
data: null
};
}
await collection.deleteOne({ _id: new ObjectId(id) });
return {
success: true,
message: "${name} deleted successfully",
data: doc as ${pluralName}
};
} catch (error) {
return {
success: false,
message: error instanceof Error ? error.message : "Failed to delete ${name.toLowerCase()}",
data: null
};
}
};
}
// ! -- CUSTOM METHODS --
// You can add custom methods or business logic below this line
// For example:
// export class Custom${name}Repository extends ${name}Repository {
// customMethod = async () => {
// // Your custom logic here
// }
// }
export const Repository = new ${name}Repository();`;
// src/generators/languages/typescript/templates/framework/elysia/schema/mongoose.ts
var generateMongooseSchema2 = (name, fields) => {
const mapTypeToMongoose = (zodType) => {
const typeMap = {
string: "String",
number: "Number",
boolean: "Boolean",
date: "Date",
array: "Array",
object: "Object"
};
return typeMap[zodType] || "String";
};
return `import { Elysia, t } from 'elysia'
import { db } from '../../config';
import { Document, Schema } from 'mongoose';
// Definisi interface untuk tipe data
export interface Create${name} {
${fields.map((f) => `${f.name}: ${f.type === "number" ? "number" : f.type === "boolean" ? "boolean" : "string"};`).join(`
`)}
}
export type Update${name} = Partial<Create${name}>;
export interface ${pluralize(name)} extends Document, Create${name} {
_id: typeof db.Types.ObjectId;
createdAt: Date;
updatedAt: Date;
}
// Mongoose schema
const ${name.toLowerCase()}Schema = new Schema<${pluralize(name)}>(
{
${fields.map((f) => `${f.name}: { type: ${mapTypeToMongoose(f.type)}, required: true }`).join(`,
`)}
},
{
timestamps: true,
versionKey: false
}
);
// Mongoose model
export const ${name} = db.model<${pluralize(name)}>('${name}', ${name.toLowerCase()}Schema);
// Elysia validation models untuk API routes
export const ${name}Model = {
create: t.Object({
${fields.map((f) => `${f.name}: t.${f.type.charAt(0).toUpperCase() + f.type.slice(1)}()`).join(`,
`)}
}),
update: t.Object({
${fields.map((f) => `${f.name}: t.${f.type.charAt(0).toUpperCase() + f.type.slice(1)}({ optional: true })`).join(`,
`)}
}),
id: t.Object({
id: t.String({
pattern: '^[0-9a-fA-F]{24}$',
error: 'Invalid ObjectId format'
})
})
}
// Plugin Elysia untuk model
export const ${name}Schema = new Elysia()
.model({
create: ${name}Model.create,
update: ${name}Model.update,
id: ${name}Model.id
})`;
};
// src/generators/languages/typescript/templates/framework/elysia/schema/mongodb.ts
var generateMongodbSchema2 = (name, fields) => `import { Elysia, t } from 'elysia'
import { ObjectId } from 'mongodb'
// Define models
const models = {
create: t.Object({
${fields.map((f) => `${f.name}: t.${f.type.charAt(0).toUpperCase() + f.type.slice(1)}()`).join(`,
`)}
}),
update: t.Object({
${fields.map((f) => `${f.name}: t.${f.type.charAt(0).toUpperCase() + f.type.slice(1)}({ optional: true })`).join(`,
`)}
}),
id: t.Object({
id: t.String({
pattern: '^[0-9a-fA-F]{24}$',
error: 'Invalid ObjectId format'
})
})
}
// Create plugin with models
export const ${name}Schema = new Elysia()
.model(models)
// Types from model
export type Create${name} = typeof models.create.static
export type Update${name} = typeof models.update.static
export type ${name}Id = typeof models.id.static
export type ${pluralize(name)} = Create${name} & {
_id: ObjectId
createdAt: Date
updatedAt: Date
}
// Export models for routes usage
export const ${name}Model = models`;
// src/generators/languages/typescript/templates/framework/elysia/schema/sql.ts
var generateSqlSchema2 = (name, fields) => `import { Elysia, t } from 'elysia'
// Define models
const models = {
create: t.Object({
${fields.map((f) => `${f.name}: t.${f.type.charAt(0).toUpperCase() + f.type.slice(1)}()`).join(`,
`)}
}),
update: t.Object({
${fields.map((f) => `${f.name}: t.${f.type.charAt(0).toUpperCase() + f.type.slice(1)}({ optional: true })`).join(`,
`)}
}),
id: t.Object({
id: t.Numeric()
})
}
// Create plugin with models
export const ${name}Schema = new Elysia()
.model(models)
// Types from model
export type Create${name} = typeof models.create.static
export type Update${name} = typeof models.update.static
export type ${name}Id = typeof models.id.static
export type ${pluralize(name)} = Create${name} & ${name}Id & {
createdAt: Date
updatedAt: Date
}
// Export models for routes usage
export const ${name}Model = models`;
// src/generators/languages/typescript/templates/framework/elysia/service/mongoose.ts
var generateMongooseService2 = (name, pluralName) => `import { Elysia } from 'elysia'
import { ${name} } from './${name.toLowerCase()}.schema'
import type { Create${name}, Update${name}, ${pluralName} } from './${name.toLowerCase()}.schema'
export type Result<T> = {
success: boolean;
message?: string;
data: T | null;
error?: unknown;
};
// Define service methods
const ${name.toLowerCase()}Methods = {
create: async(data: Create${name}): Promise<Result<${pluralName}>> => {
try {
const ${name.toLowerCase()} = new ${name}(data);
const saved${name} = await ${name.toLowerCase()}.save();
return {
success: true,
message: "${name} created successfully",
data: saved${name}
};
} catch (error) {
throw error;
}
},
getAll: async(): Promise<Result<${pluralName}[]>> => {
try {
const ${pluralName.toLowerCase()} = await ${name}.find();
return {
success: true,
data: ${pluralName.toLowerCase()}
};
} catch (error) {
throw error;
}
},
getById: async(id: string): Promise<Result<${pluralName}>> => {
try {
const ${name.toLowerCase()} = await ${name}.findById(id);
if (!${name.toLowerCase()}) {
throw new Error("${name} not found");
}
return {
success: true,
data: ${name.toLowerCase()}
};
} catch (error) {
throw error;
}
},
update: async(id: string, data: Update${name}): Promise<Result<${pluralName}>> => {
try {
const ${name.toLowerCase()} = await ${name}.findByIdAndUpdate(
id,
{ ...data },
{ new: true }
);
if (!${name.toLowerCase()}) {
throw new Error("${name} not found");
}
return {
success: true,
message: "${name} updated successfully",
data: ${name.toLowerCase()}
};
} catch (error) {
throw error;
}
},
delete: async(id: string): Promise<Result<${pluralName}>> => {
try {
const ${name.toLowerCase()} = await ${name}.findByIdAndDelete(id);
if (!${name.toLowerCase()}) {
throw new Error("${name} not found");
}
return {
success: true,
message: "${name} deleted successfully",
data: ${name.toLowerCase()}
};
} catch (error) {
throw error;
}
}
}
// Create service
export const Service = new Elysia({ name: 'Service.${name}' })
.state('${pluralName.toLowerCase()}', ${name.toLowerCase()}Methods)`;
// src/generators/languages/typescript/templates/framework/elysia/service/mongodb.ts
var generateMongodbService2 = (name, pluralName) => `import { Elysia } from 'elysia'
import { Repository as ${name} } from './${name.toLowerCase()}.repository'
import type { Create${name}, Update${name}, ${pluralName} } from './${name.toLowerCase()}.schema'
import type { Result } from './${name.toLowerCase()}.repository'
// Define service methods
const ${name.toLowerCase()}Methods = {
create: async (data: Create${name}): Promise<Result<${pluralName}>> => {
try {
return await ${name}.create(data)
} catch (error) {
console.error("Service error creating ${name.toLowerCase()}:", error)
return {
success: false,
message: error instanceof Error ? error.message : "Failed to create ${name.toLowerCase()}",
data: null
}
}
},
getAll: async (): Promise<Result<${pluralName}[]>> => {
try {
return await ${name}.findAll()
} catch (error) {
console.error("Service error getting all ${pluralName.toLowerCase()}:", error)
return {
success: false,
message: error instanceof Error ? error.message : "Failed to get all ${pluralName.toLowerCase()}",
data: null
}
}
},
getById: async (id: string): Promise<Result<${pluralName}>> => {
try {
return await ${name}.findById({ id })
} catch (error) {
console.error("Service error getting ${name.toLowerCase()} by id:", error)
return {
success: false,
message: error instanceof Error ? error.message : "Failed to get ${name.toLowerCase()} by id",
data: null
}
}
},
update: async (id: string, data: Update${name}): Promise<Result<${pluralName}>> => {
try {
return await ${name}.update({ id }, data)
} catch (error) {
console.error("Service error updating ${name.toLowerCase()}:", error)
return {
success: false,
message: error instanceof Error ? error.message : "Failed to update ${name.toLowerCase()}",
data: null
}
}
},
delete: async (id: string): Promise<Result<${pluralName}>> => {
try {
return await ${name}.delete({ id })
} catch (error) {
console.error("Service error deleting ${name.toLowerCase()}:", error)
return {
success: false,
message: error instanceof Error ? error.message : "Failed to delete ${name.toLowerCase()}",
data: null
}
}
}
}
// Create service
export const Service = new Elysia({ name: 'Service.${name}' })
.state('${pluralName.toLowerCase()}', ${name.toLowerCase()}Methods)`;
// src/generators/languages/typescript/templates/framework/elysia/service/sql.ts
var generateSqlService2 = (name, pluralName) => `import { Elysia } from 'elysia'
import { Repository } from './${name.toLowerCase()}.repository'
import type { Create${name}, Update${name} } from './${name.toLowerCase()}.schema'
// Define service methods
const ${name.toLowerCase()}Methods = {
create: async (data: Create${name}) => {
try {
return await Repository.create(data);
} catch (error) {
console.error("Service error creating ${name.toLowerCase()}:", error);
throw error;
}
},
getAll: async () => {
try {
return await Repository.findAll();
} catch (error) {
console.error("Service error getting all ${pluralName.toLowerCase()}:", error);
throw error;
}
},
getById: async (id: number) => {
try {
return await Repository.findById({ id });
} catch (error) {
console.error("Service error getting ${name.toLowerCase()} by id:", error);
throw error;
}
},
update: async (id: number, data: Update${name}) => {
try {
return await Repository.update({ id }, data);
} catch (error) {
console.error("Service error updating ${name.toLowerCase()}:", error);
throw error;
}
},
delete: async (id: number) => {
try {
return await Repository.delete({ id });
} catch (error) {
console.error("Service error deleting ${name.toLowerCase()}:", error);
throw error;
}
}
}
// Create service
export const Service = new Elysia({ name: 'Service.${name}' })
.state('${pluralName.toLowerCase()}', ${name.toLowerCase()}Methods)`;
// src/generators/languages/typescript/templates/framework/elysia/controller.ts
var generateController2 = (name, pluralName) => `import { Elysia } from 'elysia'
import { Service } from './${name.toLowerCase()}.service'
import { ${name}Model } from './${name.toLowerCase()}.schema'
export const ${name} = new Elysia()
.use(Service)
.group('/${pluralName.toLowerCase()}', app => app
.get('/',
async ({ store: { ${pluralName.toLowerCase()} } }) => {
const result = await ${pluralName.toLowerCase()}.getAll()
return result
}
)
.get('/:id',
async ({ params: { id }, store: { ${pluralName.toLowerCase()} } }) => {
const result = await ${pluralName.toLowerCase()}.getById(id)
return result
},
{ params: ${name}Model.id }
)
.post('/',
async ({ body, store: { ${pluralName.toLowerCase()} } }) => {
const result = await ${pluralName.toLowerCase()}.create(body)
return result
},
{ body: ${name}Model.create }
)
.put('/:id',
async ({ params: { id }, body, store: { ${pluralName.toLowerCase()} } }) => {
const result = await ${pluralName.toLowerCase()}.update(id, body)
return result
},
{
params: ${name}Model.id,
body: ${name}Model.update
}
)
.delete('/:id',
async ({ params: { id }, store: { ${pluralName.toLowerCase()} } }) => {
const result = await ${pluralName.toLowerCase()}.delete(id)
return result
},
{ params: ${name}Model.id }
)
)`;
// src/generators/languages/typescript/templates/framework/elysia/server.ts
var generateServer2 = () => `import { Elysia } from 'elysia'
import { cors } from '@elysiajs/cors'
import { swagger } from '@elysiajs/swagger'
import { NotFoundError, DatabaseError, ValidationError, handleError } from './error'
import { router } from './router'
const app = new Elysia()
// Register custom errors
.error({
NotFoundError,
DatabaseError,
ValidationError
})
// Global error handler
.onError(({ code, error, set }) => {
console.error(\`[Error] \${code}:\`, error);
const { status, body } = handleError(code, error);
set.status = status;
return body;
})
// Other plugins
.use(swagger({
documentation: {
info: {
title: 'API Documentation',
version: '1.0.0'
}
}
}))
.use(cors())
// Routes
.get('/', () => ({
success: true,
message: 'API is running',
data: {
timestamp: new Date().toISOString()
}
}))
.use(router)
.listen(3000)
console.log('\uD83E\uDD8A Server running at', app.server?.hostname, 'on port', app.server?.port)
export type App = typeof app`;
// src/generators/languages/typescript/templates/framework/elysia/error.ts
var generateError2 = () => `// Custom error types
export class NotFoundError extends Error {
constructor(resource: string = 'Resource', id?: string | number) {
super(id
? \`\${resource} dengan ID \${id} tidak ditemukan\`
: \`\${resource} tidak ditemukan\`);
this.name = 'NotFoundError';
}
}
export class DatabaseError extends Error {
constructor(message: string = 'Terjadi kesalahan database') {
super(message);
this.name = 'DatabaseError';
}
}
export class ValidationError extends Error {
constructor(message: string = 'Data tidak valid') {
super(message);
this.name = 'ValidationError';
}
}
// Simplified error mapping
export const ERROR_MAP = {
// Custom errors
NotFoundError: { status: 404, code: 'NOT_FOUND' },
DatabaseError: { status: 500, code: 'DATABASE_ERROR' },
ValidationError: { status: 400, code: 'VALIDATION_ERROR' },
// Elysia built-in errors
NOT_FOUND: { status: 404, code: 'ROUTE_NOT_FOUND', message: 'Route tidak ditemukan' },
VALIDATION: { status: 400, code: 'VALIDATION_ERROR' },
PARSE: { status: 400, code: 'PARSE_ERROR', message: 'Format data tidak valid' },
INTERNAL_SERVER_ERROR: { status: 500, code: 'INTERNAL_SERVER_ERROR' },
INVALID_COOKIE_SIGNATURE: { status: 400, code: 'INVALID_COOKIE' },
UNKNOWN: { status: 500, code: 'UNKNOWN_ERROR' }
} as const;
// Simplified error handler
export const handleError = (code: string | number, error: unknown) => {
const errorKey = typeof code === 'string' ? code : 'UNKNOWN';
const errorConfig = ERROR_MAP[errorKey as keyof typeof ERROR_MAP] || ERROR_MAP.UNKNOWN;
let message = 'Terjadi kesalahan internal server';
if (error instanceof Error) {
message = error.message;
} else if (typeof error === 'string') {
message = error;
}
// Use predefined message if available
if ('message' in errorConfig && typeof errorConfig.message === 'string') {
message = errorConfig.message;
}
return {
status: errorConfig.status,
body: {
success: false,
error: {
code: errorConfig.code,
message
},
data: null
}
};
};`;
// src/generators/languages/typescript/templates/framework/hono/repository/mariadb.ts
var generateMariadbRepository3 = (name, pluralName) => `import { db } from "../../config";
import type { Create${name}, Update${name}, ${pluralName}, ${name}Id } from "./${name.toLowerCase()}.schema";
import { ${name} } from "./${name.toLowerCase()}.schema";
export type Result<T> = {
success: boolean;
message?: string;
data: T | null;
error?: unknown;
};
export class ${name}Repository {
private readonly table = "${pluralName.toLowerCase()}";
create = async (data: Create${name}): Promise<Result<${pluralName}>> => {
try {
const fields = Object.keys(data);
const values = Object.values(data);
const placeholders = values.map(() => '?').join(', ');
const result = await db.query(\`
INSERT INTO \${this.table}
(\${fields.join(', ')}, createdAt, updatedAt)
VALUES (\${placeholders}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
\`, values);
const newItem = await db.query(\`
SELECT *
FROM \${this.table}
WHERE id = ?
\`, [result.insertId]);
if (!newItem?.[0]) {
throw new Error("Failed to create ${name.toLowerCase()}");
}
return {
success: true,
message: "${name} created successfully",
data: new ${name}(newItem[0]) as ${pluralName}
};
} catch (error) {
console.error('Error in create:', error);
throw new Error(error instanceof Error ? error.message : "Failed to create ${name.toLowerCase()}");
}
};
findAll = async (): Promise<Result<${pluralName}[]>> => {
try {
const rows = await db.query(\`
SELECT *
FROM \${this.table}
ORDER BY id DESC
\`);
return {
success: true,
data: rows.map((row: ${name}) => new ${name}(row) as ${pluralName})
};
} catch (error) {
console.error('Error in findAll:', error);
throw new Error("Failed to fetch ${pluralName.toLowerCase()}");
}
};
findById = async ({ id }: ${name}Id): Promise<Result<${pluralName}>> => {
try {
const row = await db.query(\`
SELECT *
FROM \${this.table}
WHERE id = ?
\`, [id]);
if (!row?.[0]) {
throw new Error("${name} not found");
}
return {
success: true,
data: new ${name}(row[0]) as ${pluralName}
};
} catch (error) {
console.error('Error in findById:', error);
throw new Error(error instanceof Error ? error.message : "Failed to find ${name.toLowerCase()}");
}
};
update = async ({ id }: ${name}Id, data: Update${name}): Promise<Result<${pluralName}>> => {
try {
const fields = Object.keys(data);
const values = Object.values(data);
const setClause = fields
.map(field => \`\${field} = ?\`)
.join(', ');
await db.query(\`
UPDATE \${this.table}
SET \${setClause}, updatedAt = CURRENT_TIMESTAMP
WHERE id = ?
\`, [...values, id]);
const row = await db.query(\`
SELECT *
FROM \${this.table}
WHERE id = ?
\`, [id]);
if (!row?.[0]) {
throw new Error("${name} not found");
}
return {
success: true,
message: "${name} updated successfully",
data: new ${name}(row[0]) as ${pluralName}
};
} catch (error) {
console.error('Error in update:', error);
throw new Error(error instanceof Error ? error.message : "Failed to update ${name.toLowerCase()}");
}
};
delete = async ({ id }: ${name}Id): Promise<Result<${pluralName}>> => {
try {
const row = await db.query(\`
SELECT *
FROM \${this.table}
WHERE id = ?
\`, [id]);
if (!row?.[0]) {
throw new Error("${name} not found");
}
await db.query(\`
DELETE FROM \${this.table}
WHERE id = ?
\`, [id]);
return {
success: true,
message: "${name} deleted successfully",
data: new ${name}(row[0]) as ${pluralName}
};
} catch (error) {
console.error('Error in delete:', error);
throw new Error(error instanceof Error ? error.message : "Failed to delete ${name.toLowerCase()}");
}
};
}
// ! -- CUSTOM METHODS --
// You can add custom methods or business logic below this line
// For example:
// export class Custom${name}Repository extends ${name}Repository {
// customMethod = async () => {
// // Your custom logic here
// }
// }
export const Repository = new ${name}Repository();`;
// src/generators/languages/typescript/templates/framework/hono/repository/mongodb.ts
var generateMongoRepository3 = (name, pluralName) => `import { ObjectId } from "mongodb";
import { db } from "../../config";
import type { Create${name}, Update${name}, ${pluralName}, ${name}Id } from "./${name.toLowerCase()}.schema";
import { ${name} } from "./${name.toLowerCase()}.schema";
import { HTTPException } from "hono/http-exception";
export class ${name}Repository {
private readonly collection = "${pluralName.toLowerCase()}";
private getCollection = async () => {
return db.collection(this.collection);
};
create = async (data: Create${name}) => {
try {
const doc = {
...data,
createdAt: new Date(),
updatedAt: new Date()
} as const;
const collection = await this.getCollection();
const result = await collection.insertOne(doc);
if (!result.acknowledged) {
throw new HTTPException(500, { message: "Failed to create ${name.toLowerCase()}" });
}
return {
success: true,
message: "${name} created successfully",
data: new ${name}({ ...doc, _id: result.insertedId }) as ${pluralName}
};
} catch (error) {
console.error("Repository error creating ${name.toLowerCase()}:", error);
throw error;
}
};
findAll = async () => {
try {
const collection = await this.getCollection();
const docs = await collection
.find({})
.sort({ _id: -1 })
.toArray() as ${pluralName}[];
return {
success: true,
data: docs.map(doc => new ${name}(doc) as ${pluralName})
};
} catch (error) {
console.error("Repository error fetching ${pluralName.toLowerCase()}:", error);
throw error;
}
};
findById = async ({ id }: ${name}Id) => {
try {
const collection = await this.getCollection();
const doc = await collection
.findOne({ _id: new ObjectId(id) }) as ${pluralName} | null;
if (!doc) {
throw new HTTPException(404, { message: \`${name} with id \${id} not found\` });
}
return {
success: true,
data: new ${name}(doc) as ${pluralName}
};
} catch (error) {
console.error("Repository error finding ${name.toLowerCase()}:", error);
throw error;
}
};
update = async ({ id }: ${name}Id, data: Update${name}) => {
try {
const collection = await this.getCollection();
const result = await collection
.findOneAndUpdate(
{ _id: new ObjectId(id) },
{
$set: {
...data,
updatedAt: new Date()
}
},
{ returnDocument: 'after' }
);
if (!result) {
throw new HTTPException(404, { message: \`${name} with id \${id} not found\` });
}
return {
success: true,
message: "${name} updated successfully",
data: new ${name}(result) as ${pluralName}
};
} catch (error) {
console.error("Repository error updating ${name.toLowerCase()}:", error);
throw error;
}
};
delete = async ({ id }: ${name}Id) => {
try {
const collection = await this.getCollection();
const doc = await collection
.findOne({ _id: new ObjectId(id) });
if (!doc) {
throw new HTTPException(404, { message: \`${name} with id \${id} not found\` });
}
await collection.deleteOne({ _id: new ObjectId(id) });
return {
success: true,
message: "${name} deleted successfully",
data: new ${name}(doc) as ${pluralName}
};
} catch (error) {
console.error("Repository error deleting ${name.toLowerCase()}:", error);
throw error;
}
};
}
// ! -- CUSTOM METHODS --
// You can add custom methods or business logic below this line
// For example:
// export class Custom${name}Repository extends ${name}Repository {
// customMethod = async () => {
// // Your custom logic here
// }
// }
export const Repository = new ${name}Repository();`;
// src/generators/languages/typescript/templates/framework/hono/repository/postgresql.ts
var generatePostgresRepository3 = (name, pluralName) => `import { sql } from "../../config";
import type { Create${name}, Update${name}, ${pluralName}, ${name}Id } from "./${name.toLowerCase()}.schema";
import { ${name} } from "./${name.toLowerCase()}.schema";
import { HTTPException } from "hono/http-exception";
export class ${name}Repository {
private readonly table = "${pluralName.toLowerCase()}";
create = async (data: Create${name}) => {
try {
const [result] = await sql\`
INSERT INTO \${sql(this.table)} \${sql(data)}
RETURNING *
\`;
return {
success: true,
message: "${name} created successfully",
data: new ${name}(result) as ${pluralName}
};
} catch (error) {
console.error("Error creating ${name.toLowerCase()}:", error);
throw error;
}
};
findAll = async () => {
try {
const result = await sql\`SELECT * FROM \${sql(this.table)}\`;
return {
success: true,
data: result.map((row: ${pluralName}) => new ${name}(row) as ${pluralName})
};
} catch (error) {
console.error("Error finding all ${pluralName.toLowerCase()}:", error);
throw error;
}
};
findById = async ({ id }: ${name}Id) => {
try {
const [result] = await sql\`SELECT * FROM \${sql(this.table)} WHERE "id" = \${id}\`;
if (!result) {
throw new HTTPException(404, { message: "${name} not found" });
}
return {
success: true,
data: new ${name}(result) as ${pluralName}
};
} catch (error) {
console.error("Error finding ${name.toLowerCase()} by id:", error);
throw error;
}
};
update = async ({ id }: ${name}Id, data: Update${name}) => {
try {
const [result] = await sql\`
UPDATE \${sql(this.table)}
SET \${sql(data)}, "updatedAt" = NOW()
WHERE "id" = \${id}
RETURNING *
\`;
if (!result) {
throw new HTTPException(404, { message: "${name} not found" });
}
return {
success: true,
message: "${name} updated successfully",
data: new ${name}(result) as ${pluralName}
};
} catch (error) {
console.error("Error updating ${name.toLowerCase()}:", error);
throw error;
}
};
delete = async ({ id }: ${name}Id) => {
try {
return await sql.begin(async (tx) => {
const [${name.toLowerCase()}] = await tx\`SELECT * FROM \${sql(this.table)} WHERE "id" = \${id}\`;
if (!${name.toLowerCase()}) {
throw new HTTPException(404, { message: "${name} not found" });
}
await tx\`DELETE FROM \${sql(this.table)} WHERE "id" = \${id}\`;
return {
success: true,
message: "${name} deleted successfully",
data: new ${name}(${name.toLowerCase()}) as ${pluralName}
};
});
} catch (error) {
console.error("Error deleting ${name.toLowerCase()}:", error);
throw error;
}
};
}
// ! -- CUSTOM METHODS --
// You can add custom methods or business logic below this line
// For example:
// export class Custom${name}Repository extends ${name}Repository {
// customMethod = async () => {
// // Your custom logic here
// }
// }
export const Repository = new ${name}Repository();`;
// src/generators/languages/typescript/templates/framework/hono/repository/sqlite.ts
var generateSqliteRepository3 = (name, pluralName) => `import { db } from "../../config";
import type { Create${name}, Update${name}, ${pluralName}, ${name}Id } from "./${name.toLowerCase()}.schema";
import { ${name} } from "./${name.toLowerCase()}.schema";
import { HTTPException } from "hono/http-exception";
// Tipe untuk data dari SQLite (timestamps sebagai string)
type SQLite${name} = Omit<${pluralName}, 'createdAt' | 'updatedAt'> & {
createdAt: string;
updatedAt: string;
};
export class ${name}Repository {
private readonly table = "${pluralName.toLowerCase()}";
private convertDates(${name.toLowerCase()}: SQLite${name}): ${pluralName} {
return new ${name}({
...${name.toLowerCase()},
createdAt: new Date(${name.toLowerCase()}.createdAt),
updatedAt: new Date(${name.toLowerCase()}.updatedAt)
}) as ${pluralName};
}
create = async (data: Create${name}) => {
try {
const fields = Object.keys(data);
const columns = fields.join(', ');
const placeholders = fields.map(f => \`$\${f}\`).join(', ');
const params = Object.fromEntries(fields.map(f => [\`$\${f}\`, data[f as keyof Create${name}]]));
const newItem = db.query(\`
INSERT INTO \${this.table}
(\${columns}, createdAt, updatedAt)
VALUES (\${placeholders}, datetime('now'), datetime('now'))
RETURNING *;
\`).get(params) as SQLite${name};
if (!newItem) throw new HTTPException(400, { message: "Failed to create ${name.toLowerCase()}" });
return {
success: true,
message: "${name} created successfully",
data: this.convertDates(newItem)
};
} catch (error) {
console.error("Error creating ${name.toLowerCase()}:", error);
throw error;
}
};
findAll = async () => {
try {
const query = db.query(\`SELECT * FROM \${this.table}\`);
const rows = query.all() as SQLite${name}[];
return {
success: true,
data: rows.map(this.convertDates)
};
} catch (error) {
console.error("Error finding all ${pluralName.toLowerCase()}:", error);
throw error;
}
};
findById = async ({ id }: ${name}Id) => {
try {
const query = db.query(\`
SELECT *
FROM \${this.table}
WHERE id = $id
\`);
const row = query.get({ $id: id }) as SQLite${name} | undefined;
if (!row) {
throw new HTTPException(404, { message: "${name} not found" });
}
return {
success: true,
data: this.convertDates(row)
};
} catch (error) {
console.error("Error finding ${name.toLowerCase()} by id:", error);
throw error;
}
};
update = async ({ id }: ${name}Id, data: Update${name}) => {
try {
const fields = Object.keys(data);
const setClause = fields.map(f => \`\${f} = $\${f}\`).join(', ');
const params = { $id: id, ...Object.fromEntries(fields.map(f => [\`$\${f}\`, data[f as keyof Update${name}]])) };
db.query(\`
UPDATE \${this.table}
SET \${setClause}, updatedAt = datetime('now')
WHERE id = $id
\`).run(params);
const row = db.query(\`SELECT * FROM \${this.table} WHERE id = $id\`)
.get({ $id: id }) as SQLite${name};
if (!row) throw new HTTPException(404, { message: "${name} not found" });
return {
success: true,
message: "${name} updated successfully",
data: this.convertDates(row)
};
} catch (error) {
console.error("Error updating ${name.toLowerCase()}:", error);
throw error;
}
};
delete = async ({ id }: ${name}Id) => {
try {
const findQuery = db.query(\`
SELECT *
FROM \${this.table}
WHERE id = $id
\`);
const row = findQuery.get({ $id: id }) as SQLite${name} | undefined;
if (!row) {
throw new HTTPException(404, { message: "${name} not found" });
}
const deleteQuery = db.query(\`DELETE FROM \${this.table} WHERE id = $id\`);
deleteQuery.run({ $id: id });
return {
success: true,
message: "${name} deleted successfully",
data: this.convertDates(row)
};
} catch (error) {
console.error("Error deleting ${name.toLowerCase()}:", error);
throw error;
}
};
}
// ! -- CUSTOM METHODS --
// You can add custom methods or business logic below this line
// For example:
// export class Custom${name}Repository extends ${name}Repository {
// customMethod = async () => {
// // Your custom logic here
// }
// }
export const Repository = new ${name}Repository();`;
// src/generators/languages/typescript/templates/framework/hono/schema/sql.ts
var generateSqlSchema3 = (name, fields) => `import { z } from "zod"
export class ${name} {
constructor(data: Partial<${pluralize(name)}>) {
Object.assign(this, data)
}
}
const ${name}Schema = z.object({
${fields.map((f) => `${f.name}: z.${f.type}()`).join(`,
`)}
})
const WithIdSchema = z.object({
id: z.number()
})
const TimestampSchema = z.object({
createdAt: z.date(),
updatedAt: z.date()
})
export const ${name}IdValidate = z.object({
id: z.coerce.number().positive("ID harus positif")
})
export const Create${name}Validate = ${name}Schema
export const ${pluralize(name)}Validate = ${name}Schema
.merge(WithIdSchema)
.merge(TimestampSchema)
export const Update${name}Validate = ${name}Schema.partial()
export type Create${name} = z.infer<typeof Create${name}Validate>
export type ${pluralize(name)} = z.infer<typeof ${pluralize(name)}Validate>
export type Update${name} = z.infer<typeof Update${name}Validate>
export type ${name}Id = z.infer<typeof ${name}IdValidate>
`;
// src/generators/languages/typescript/templates/framework/hono/schema/mongodb.ts
var generateMongodbSchema3 = (name, fields) => `import { z } from "zod"
import { ObjectId } from "mongodb"
export class ${name} {
constructor(data: Partial<${pluralize(name)}>) {
Object.assign(this, data)
}
}
const ${name}Schema = z.object({
${fields.map((f) => `${f.name}: z.${f.type}()`).join(`,
`)}
})
const WithIdSchema = z.object({
_id: z.instanceof(ObjectId)
})
const TimestampSchema = z.object({
createdAt: z.date(),
updatedAt: z.date()
})
export const ${name}IdValidate = z.object({
id: z.string().regex(/^[0-9a-fA-F]{24}$/, "Invalid ObjectId format")
})
export const Create${name}Validate = ${name}Schema
export const ${pluralize(name)}Validate = ${name}Schema
.merge(WithIdSchema)
.merge(TimestampSchema)
export const Update${name}Validate = ${name}Schema.partial()
export type Create${name} = z.infer<typeof Create${name}Validate>
export type ${pluralize(name)} = z.infer<typeof ${pluralize(name)}Validate>
export type Update${name} = z.infer<typeof Update${name}Validate>
export type ${name}Id = z.infer<typeof ${name}IdValidate>
`;
// src/generators/languages/typescript/templates/framework/hono/schema/mongoose.ts
var generateMongooseSchema3 = (name, fields) => {
const mapTypeToMongoose = (zodType) => {
const typeMap = {
string: "String",
number: "Number",
boolean: "Boolean",
date: "Date",
array: "Array",
object: "Object"
};
return typeMap[zodType] || "String";
};
const mapTypeToZod = (type) => {
const typeMap = {
string: "z.string()",
number: "z.number()",
boolean: "z.boolean()",
date: "z.date()",
array: "z.array(z.any())",
object: "z.object({})"
};
return typeMap[type] || "z.string()";
};
return `import { z } from "zod";
import mongoose from "mongoose";
// Definisi schema mongoose
const ${name.toLowerCase()}Schema = new mongoose.Schema({
${fields.map((f) => `${f.name}: {
type: ${mapTypeToMongoose(f.type)},
required: true
}`).join(`,
`)}
}, {
timestamps: true
});
// Model mongoose
export const ${name} = mongoose.model('${name}', ${name.toLowerCase()}Schema);
// Zod schema untuk validasi
const ${name}Schema = z.object({
${fields.map((f) => `${f.name}: ${mapTypeToZod(f.type)}`).join(`,
`)}
})
const TimestampSchema = z.object({
createdAt: z.date(),
updatedAt: z.date()
})
export const ${name}IdValidate = z.object({
id: z.string().refine((val) => mongoose.Types.ObjectId.isValid(val), {
message: "ID harus berupa ObjectId yang valid"
})
})
export const Create${name}Validate = ${name}Schema
export const ${pluralize(name)}Validate = ${name}Schema
.merge(z.object({
_id: z.instanceof(mongoose.Types.ObjectId).or(z.string())
}))
.merge(TimestampSchema)
export const Update${name}Validate = ${name}Schema.partial()
export type Create${name} = z.infer<typeof Create${name}Validate>
export type ${pluralize(name)} = z.infer<typeof ${pluralize(name)}Validate>
export type Update${name} = z.infer<typeof Update${name}Validate>
export type ${name}Id = z.infer<typeof ${name}IdValidate>
`;
};
// src/generators/languages/typescript/templates/framework/hono/service/mongodb.ts
var generateMongodbService3 = (name, pluralName) => `import { Repository as ${name} } from "./${name.toLowerCase()}.repository";
import type { Create${name}, Update${name} } from "./${name.toLowerCase()}.schema";
export const Service = {
create: async (data: Create${name}) => {
try {
return await ${name}.create(data);
} catch (error) {
console.error("Service error creating ${name.toLowerCase()}:", error);
throw error;
}
},
getAll: async () => {
try {
return await ${name}.findAll();
} catch (error) {
console.error("Service error getting all ${pluralName.toLowerCase()}:", error);
throw error;
}
},
getById: async (id: string) => {
try {
return await ${name}.findById({ id });
} catch (error) {
console.error("Service error getting ${name.toLowerCase()} by id:", error);
throw error;
}
},
update: async (id: string, data: Update${name}) => {
try {
return await ${name}.update({ id }, data);
} catch (error) {
console.error("Service error updating ${name.toLowerCase()}:", error);
throw error;
}
},
delete: async (id: string) => {
try {
return await ${name}.delete({ id });
} catch (error) {
console.error("Service error deleting ${name.toLowerCase()}:", error);
throw error;
}
}
};`;
// src/generators/languages/typescript/templates/framework/hono/service/mongoose.ts
var generateMongooseService3 = (name, pluralName) => `import { db } from '../../config';
import type { Create${name}, Update${name} } from './${name.toLowerCase()}.schema';
import { ${name} } from './${name.toLowerCase()}.schema';
import { HTTPException } from 'hono/http-exception';
export class ${name}Service {
create = async (data: Create${name}) => {
try {
const ${name.toLowerCase()} = new ${name}(data);
const saved${name} = await ${name.toLowerCase()}.save();
return {
success: true,
message: "${name} created successfully",
data: saved${name}
};
} catch (error) {
console.error("Error creating ${name.toLowerCase()}:", error);
throw error;
}
};
getAll = async () => {
try {
const ${pluralName.toLowerCase()} = await ${name}.find();
return {
success: true,
data: ${pluralName.toLowerCase()}
};
} catch (error) {
console.error("Error fetching ${pluralName.toLowerCase()}:", error);
throw error;
}
};
getById = async (id: string) => {
try {
if (!db.Types.ObjectId.isValid(id)) {
throw new HTTPException(400, { message: "Invalid ${name.toLowerCase()} ID" });
}
const ${name.toLowerCase()} = await ${name}.findById(id);
if (!${name.toLowerCase()}) {
throw new HTTPException(404, { message: "${name} not found" });
}
return {
success: true,
data: ${name.toLowerCase()}
};
} catch (error) {
console.error("Error finding ${name.toLowerCase()}:", error);
throw error;
}
};
update = async (id: string, data: Update${name}) => {
try {
if (!db.Types.ObjectId.isValid(id)) {
throw new HTTPException(400, { message: "Invalid ${name.toLowerCase()} ID" });
}
const updated${name} = await ${name}.findByIdAndUpdate(
id,
{ ...data },
{ new: true }
);
if (!updated${name}) {
throw new HTTPException(404, { message: "${name} not found" });
}
return {
success: true,
message: "${name} updated successfully",
data: updated${name}
};
} catch (error) {
console.error("Error updating ${name.toLowerCase()}:", error);
throw error;
}
};
delete = async (id: string) => {
try {
if (!db.Types.ObjectId.isValid(id)) {
throw new HTTPException(400, { message: "Invalid ${name.toLowerCase()} ID" });
}
const deleted${name} = await ${name}.findByIdAndDelete(id);
if (!deleted${name}) {
throw new HTTPException(404, { message: "${name} not found" });
}
return {
success: true,
message: "${name} deleted successfully",
data: deleted${name}
};
} catch (error) {
console.error("Error deleting ${name.toLowerCase()}:", error);
throw error;
}
};
}
export const Service = new ${name}Service();
`;
// src/generators/languages/typescript/templates/framework/hono/service/sql.ts
var generateSqlService3 = (name, pluralName) => `import { Repository as ${name} } from "./${name.toLowerCase()}.repository";
import type { Create${name}, Update${name} } from "./${name.toLowerCase()}.schema";
export const Service = {
create: async (data: Create${name}) => {
try {
return await ${name}.create(data);
} catch (error) {
console.error("Service error creating ${name.toLowerCase()}:", error);
throw error;
}
},
getAll: async () => {
try {
return await ${name}.findAll();
} catch (error) {
console.error("Service error getting all ${pluralName.toLowerCase()}:", error);
throw error;
}
},
getById: async (id: string) => {
try {
return await ${name}.findById({ id: Number(id) });
} catch (error) {
console.error("Service error getting ${name.toLowerCase()} by id:", error);
throw error;
}
},
update: async (id: string, data: Update${name}) => {
try {
return await ${name}.update({ id: Number(id) }, data);
} catch (error) {
console.error("Service error updating ${name.toLowerCase()}:", error);
throw error;
}
},
delete: async (id: string) => {
try {
return await ${name}.delete({ id: Number(id) });
} catch (error) {
console.error("Service error deleting ${name.toLowerCase()}:", error);
throw error;
}
}
};`;
// src/generators/languages/typescript/templates/framework/hono/controller.ts
var generateController3 = (name, pluralName) => `import { Hono } from "hono"
import { zValidator } from "@hono/zod-validator"
import { Create${name}Validate, Update${name}Validate } from "./${name.toLowerCase()}.schema"
import { Service as ${name} } from "./${name.toLowerCase()}.service"
export const ${pluralName.toLowerCase()} = new Hono()
.post('/',
zValidator('json', Create${name}Validate),
async (c) => {
const body = c.req.valid('json')
const result = await ${name}.create(body)
return c.json(result, 201)
}
)
.get('/',
async (c) => {
const result = await ${name}.getAll()
return c.json(result)
}
)
.get('/:id',
async (c) => {
const { id } = c.req.param()
const result = await ${name}.getById(id)
return c.json(result)
}
)
.put('/:id',
zValidator('json', Update${name}Validate),
async (c) => {
const { id } = c.req.param()
const body = c.req.valid('json')
const result = await ${name}.update(id, body)
return c.json(result)
}
)
.delete('/:id',
async (c) => {
const { id } = c.req.param()
const result = await ${name}.delete(id)
return c.json(result)
}
)`;
// src/generators/languages/typescript/templates/framework/hono/server.ts
var generateServer3 = () => `import { Hono } from "hono"
import { cors } from "hono/cors"
import { logger } from "hono/logger"
import { router } from "./router"
import { errorHandler } from "./error"
const app = new Hono()
// Middleware
app.use("*", logger())
app.use("*", cors())
// Routes
app.route("/api", router)
// Error Handler
app.onError(errorHandler)
export default app`;
// src/generators/languages/typescript/templates/framework/hono/error.ts
var generateError3 = () => `import type { Context } from 'hono'
import { HTTPException } from 'hono/http-exception'
import { ZodError } from 'zod'
export const errorHandler = (err: Error, c: Context) => {
// Log error utk debugging
console.error("Error:", err)
// Handle Zod validation errors
if (err instanceof ZodError) {
return c.json({
success: false,
message: "Validasi gagal",
errors: err.errors.map(e => ({
field: e.path.join('.'),
message: e.message
})),
data: null
}, 400)
}
// Handle HTTP exceptions
if (err instanceof HTTPException) {
return c.json({
success: false,
message: err.message,
data: null
}, err.status)
}
// Handle other errors
return c.json({
success: false,
message: err instanceof Error ? err.message : "Terjadi kesalahan internal server",
data: null
}, 500)
}`;
// src/generators/languages/typescript/templates/framework/next/repository/postgresql.ts
var generatePostgresRepository4 = (name, pluralName) => `import { db } from "../../config";
import type { Create${name}, Update${name}, ${pluralName}, ${name}Id } from "./${name.toLowerCase()}.schema";
import { ${name} } from "./${name.toLowerCase()}.schema";
export type Result<T> = {
success: boolean;
message?: string;
data: T | null;
error?: unknown;
};
export class ${name}Repository {
private readonly table = "${pluralName.toLowerCase()}";
create = async (data: Create${name}): Promise<Result<${pluralName}>> => {
try {
const fields = Object.keys(data).map(key => \`"\${key}"\`);
const values = Object.values(data);
const placeholders = values.map((_, i) => \`$\${i + 1}\`).join(', ');
const query = \`
INSERT INTO \${this.table}
(\${fields.join(', ')}, "createdAt", "updatedAt")
VALUES (\${placeholders}, NOW(), NOW())
RETURNING *
\`;
const result = await db.query(query, values);
if (!result.rows[0]) {
throw new Error("Failed to create ${name.toLowerCase()}");
}
return {
success: true,
message: "${name} created successfully",
data: new ${name}(result.rows[0]) as ${pluralName}
};
} catch (error) {
throw new Error(error instanceof Error ? error.message : "Failed to create ${name.toLowerCase()}");
}
};
findAll = async (): Promise<Result<${pluralName}[]>> => {
try {
const result = await db.query<${pluralName}>(\`
SELECT * FROM \${this.table}
\`);
return {
success: true,
data: result.rows.map(row => new ${name}(row) as ${pluralName})
};
} catch (error) {
console.log(error)
throw new Error("Failed to fetch ${pluralName.toLowerCase()}");
}
};
findById = async ({ id }: ${name}Id): Promise<Result<${pluralName}>> => {
try {
const result = await db.query(\`
SELECT *
FROM \${this.table}
WHERE "id" = $1
\`, [id]);
if (!result.rows[0]) {
throw new Error("${name} not found");
}
return {
success: true,
data: new ${name}(result.rows[0]) as ${pluralName}
};
} catch (error) {
throw new Error(error instanceof Error ? error.message : "Failed to find ${name.toLowerCase()}");
}
};
update = async ({ id }: ${name}Id, data: Update${name}): Promise<Result<${pluralName}>> => {
try {
const fields = Object.keys(data);
const values = Object.values(data);
const setClause = fields
.map((field, i) => \`"\${field}" = $\${i + 1}\`)
.join(', ');
const query = \`
UPDATE \${this.table}
SET \${setClause}, "updatedAt" = NOW()
WHERE "id" = $\${values.length + 1}
RETURNING *
\`;
const result = await db.query(query, [...values, id]);
if (!result.rows[0]) {
throw new Error("${name} not found");
}
return {
success: true,
message: "${name} updated successfully",
data: new ${name}(result.rows[0]) as ${pluralName}
};
} catch (error) {
throw new Error(error instanceof Error ? error.message : "Failed to update ${name.toLowerCase()}");
}
};
delete = async ({ id }: ${name}Id): Promise<Result<${pluralName}>> => {
try {
const findResult = await db.query(\`
SELECT *
FROM \${this.table}
WHERE "id" = $1
\`, [id]);
if (!findResult.rows[0]) {
throw new Error("${name} not found");
}
await db.query(\`
DELETE FROM \${this.table}
WHERE "id" = $1
\`, [id]);
return {
success: true,
message: "${name} deleted successfully",
data: new ${name}(findResult.rows[0]) as ${pluralName}
};
} catch (error) {
throw new Error(error instanceof Error ? error.message : "Failed to delete ${name.toLowerCase()}");
}
};
}
// ! -- CUSTOM METHODS --
// You can add custom methods or business logic below this line
// For example:
// export class Custom${name}Repository extends ${name}Repository {
// customMethod = async () => {
// // Your custom logic here
// }
// }
export const Repository = new ${name}Repository();`;
// src/generators/languages/typescript/templates/framework/next/repository/sqlite.ts
var generateSqliteRepository4 = (name, pluralName) => `import { db } from "../../config";
import type { Create${name}, Update${name}, ${pluralName}, ${name}Id } from "./${name.toLowerCase()}.schema";
import { ${name} } from "./${name.toLowerCase()}.schema";
export type Result<T> = {
success: boolean;
message?: string;
data: T | null;
error?: unknown;
};
export class ${name}Repository {
private readonly table = "${pluralName.toLowerCase()}";
create = async (data: Create${name}): Promise<Result<${pluralName}>> => {
try {
const fields = Object.keys(data);
const values = Object.values(data);
const placeholders = values.map(() => '?').join(', ');
const query = \`
INSERT INTO \${this.table}
(\${fields.join(', ')}, createdAt, updatedAt)
VALUES (\${placeholders}, datetime('now'), datetime('now'))
RETURNING *;
\`;
const [newItem] = await db.query(query, values);
if (!newItem) {
throw new Error("Failed to create ${name.toLowerCase()}");
}
return {
success: true,
message: "${name} created successfully",
data: new ${name}(newItem) as ${pluralName}
};
} catch (error) {
throw new Error(error instanceof Error ? error.message : "Failed to create ${name.toLowerCase()}");
}
};
findAll = async (): Promise<Result<${pluralName}[]>> => {
try {
const rows = await db.query(\`
SELECT *
FROM \${this.table}
\`);
return {
success: true,
data: rows.map((row: ${pluralName}) => new ${name}(row) as ${pluralName})
};
} catch (error) {
console.log(error)
throw new Error("Failed to fetch ${pluralName.toLowerCase()}");
}
};
findById = async ({ id }: ${name}Id): Promise<Result<${pluralName}>> => {
try {
const [row] = await db.query(\`
SELECT *
FROM \${this.table}
WHERE id = ?
\`, [id]);
if (!row) {
throw new Error("${name} not found");
}
return {
success: true,
data: new ${name}(row) as ${pluralName}
};
} catch (error) {
throw new Error(error instanceof Error ? error.message : "Failed to find ${name.toLowerCase()}");
}
};
update = async ({ id }: ${name}Id, data: Update${name}): Promise<Result<${pluralName}>> => {
try {
const fields = Object.keys(data);
const values = Object.values(data);
const setClause = fields
.map(field => \`\${field} = ?\`)
.join(', ');
const query = \`
UPDATE \${this.table}
SET \${setClause}, updatedAt = datetime('now')
WHERE id = ?
\`;
await db.query(query, [...values, id]);
const [row] = await db.query(\`
SELECT *
FROM \${this.table}
WHERE id = ?
\`, [id]);
if (!row) {
throw new Error("${name} not found");
}
return {
success: true,
message: "${name} updated successfully",
data: new ${name}(row) as ${pluralName}
};
} catch (error) {
throw new Error(error instanceof Error ? error.message : "Failed to update ${name.toLowerCase()}");
}
};
delete = async ({ id }: ${name}Id): Promise<Result<${pluralName}>> => {
try {
const [row] = await db.query(\`
SELECT *
FROM \${this.table}
WHERE id = ?
\`, [id]);
if (!row) {
throw new Error("${name} not found");
}
await db.query(\`
DELETE FROM \${this.table}
WHERE id = ?
\`, [id]);
return {
success: true,
message: "${name} deleted successfully",
data: new ${name}(row) as ${pluralName}
};
} catch (error) {
throw new Error(error instanceof Error ? error.message : "Failed to delete ${name.toLowerCase()}");
}
};
}
// ! -- CUSTOM METHODS --
// You can add custom methods or business logic below this line
// For example:
// export class Custom${name}Repository extends ${name}Repository {
// customMethod = async () => {
// // Your custom logic here
// }
// }
export const Repository = new ${name}Repository()`;
// src/generators/languages/typescript/templates/framework/next/repository/mariadb.ts
var generateMariadbRepository4 = (name, pluralName) => `import { db } from "../../config";
import type { Create${name}, Update${name}, ${pluralName}, ${name}Id } from "./${name.toLowerCase()}.schema";
import { ${name} } from "./${name.toLowerCase()}.schema";
export type Result<T> = {
success: boolean;
message?: string;
data: T | null;
error?: unknown;
};
export class ${name}Repository {
private readonly table = "${pluralName.toLowerCase()}";
create = async (data: Create${name}): Promise<Result<${pluralName}>> => {
try {
const fields = Object.keys(data);
const values = Object.values(data);
const placeholders = values.map(() => '?').join(', ');
const result = await db.query(\`
INSERT INTO \${this.table}
(\${fields.join(', ')}, createdAt, updatedAt)
VALUES (\${placeholders}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
\`, values);
const newItem = await db.query(\`
SELECT *
FROM \${this.table}
WHERE id = ?
\`, [result.insertId]);
if (!newItem?.[0]) {
throw new Error("Failed to create ${name.toLowerCase()}");
}
return {
success: true,
message: "${name} created successfully",
data: new ${name}(newItem[0]) as ${pluralName}
};
} catch (error) {
console.error('Error in create:', error);
throw new Error(error instanceof Error ? error.message : "Failed to create ${name.toLowerCase()}");
}
};
findAll = async (): Promise<Result<${pluralName}[]>> => {
try {
const rows = await db.query(\`
SELECT *
FROM \${this.table}
ORDER BY id DESC
\`);
return {
success: true,
data: rows.map((row: ${pluralName}) => new ${name}(row) as ${pluralName})
};
} catch (error) {
console.error('Error in findAll:', error);
throw new Error("Failed to fetch ${pluralName.toLowerCase()}");
}
};
findById = async ({ id }: ${name}Id): Promise<Result<${pluralName}>> => {
try {
const row = await db.query(\`
SELECT *
FROM \${this.table}
WHERE id = ?
\`, [id]);
if (!row?.[0]) {
throw new Error("${name} not found");
}
return {
success: true,
data: new ${name}(row[0]) as ${pluralName}
};
} catch (error) {
console.error('Error in findById:', error);
throw new Error(error instanceof Error ? error.message : "Failed to find ${name.toLowerCase()}");
}
};
update = async ({ id }: ${name}Id, data: Update${name}): Promise<Result<${pluralName}>> => {
try {
const fields = Object.keys(data);
const values = Object.values(data);
const setClause = fields
.map(field => \`\${field} = ?\`)
.join(', ');
await db.query(\`
UPDATE \${this.table}
SET \${setClause}, updatedAt = CURRENT_TIMESTAMP
WHERE id = ?
\`, [...values, id]);
const row = await db.query(\`
SELECT *
FROM \${this.table}
WHERE id = ?
\`, [id]);
if (!row?.[0]) {
throw new Error("${name} not found");
}
return {
success: true,
message: "${name} updated successfully",
data: new ${name}(row[0]) as ${pluralName}
};
} catch (error) {
console.error('Error in update:', error);
throw new Error(error instanceof Error ? error.message : "Failed to update ${name.toLowerCase()}");
}
};
delete = async ({ id }: ${name}Id): Promise<Result<${pluralName}>> => {
try {
const row = await db.query(\`
SELECT *
FROM \${this.table}
WHERE id = ?
\`, [id]);
if (!row?.[0]) {
throw new Error("${name} not found");
}
await db.query(\`
DELETE FROM \${this.table}
WHERE id = ?
\`, [id]);
return {
success: true,
message: "${name} deleted successfully",
data: new ${name}(row[0]) as ${pluralName}
};
} catch (error) {
console.error('Error in delete:', error);
throw new Error(error instanceof Error ? error.message : "Failed to delete ${name.toLowerCase()}");
}
};
}
// ! -- CUSTOM METHODS --
// You can add custom methods or business logic below this line
// For example:
// export class Custom${name}Repository extends ${name}Repository {
// customMethod = async () => {
// // Your custom logic here
// }
// }
export const Repository = new ${name}Repository()`;
// src/generators/languages/typescript/templates/framework/next/repository/mongodb.ts
var generateMongoRepository4 = (name, pluralName) => `import { ObjectId } from "mongodb";
import { db } from "../../config";
import type { Create${name}, Update${name}, ${pluralName}, ${name}Id } from "./${name.toLowerCase()}.schema";
import { ${name} } from "./${name.toLowerCase()}.schema";
import { NotFoundError, BadRequestError } from "../../error";
export class ${name}Repository {
private readonly collection = "${pluralName.toLowerCase()}";
private getCollection = async () => {
return db.collection(this.collection);
};
create = async (data: Create${name}) => {
try {
const doc = {
...data,
createdAt: new Date(),
updatedAt: new Date()
};
const collection = await this.getCollection();
const result = await collection.insertOne(doc);
if (!result.acknowledged) {
throw new BadRequestError("Failed to create ${name.toLowerCase()}");
}
return {
success: true,
message: "${name} created successfully",
data: new ${name}({ ...doc, _id: result.insertedId }) as ${pluralName}
};
} catch (error) {
console.error("Error creating ${name.toLowerCase()}:", error);
throw error;
}
};
findAll = async () => {
try {
const collection = await this.getCollection();
const docs = await collection
.find({})
.sort({ _id: -1 })
.toArray() as ${pluralName}[];
return {
success: true,
data: docs.map(doc => new ${name}(doc) as ${pluralName})
};
} catch (error) {
console.error("Error finding all ${pluralName.toLowerCase()}:", error);
throw error;
}
};
findById = async ({ id }: ${name}Id) => {
try {
const collection = await this.getCollection();
const doc = await collection
.findOne({ _id: new ObjectId(id) }) as ${pluralName} | null;
if (!doc) {
throw new NotFoundError(\`${name} with id \${id} not found\`);
}
return {
success: true,
data: new ${name}(doc) as ${pluralName}
};
} catch (error) {
console.error("Error finding ${name.toLowerCase()} by id:", error);
throw error;
}
};
update = async ({ id }: ${name}Id, data: Update${name}) => {
try {
const collection = await this.getCollection();
const result = await collection
.findOneAndUpdate(
{ _id: new ObjectId(id) },
{
$set: {
...data,
updatedAt: new Date()
}
},
{ returnDocument: 'after' }
);
if (!result) {
throw new NotFoundError(\`${name} with id \${id} not found\`);
}
return {
success: true,
message: "${name} updated successfully",
data: new ${name}(result) as ${pluralName}
};
} catch (error) {
console.error("Error updating ${name.toLowerCase()}:", error);
throw error;
}
};
delete = async ({ id }: ${name}Id) => {
try {
const collection = await this.getCollection();
const doc = await collection
.findOne({ _id: new ObjectId(id) });
if (!doc) {
throw new NotFoundError(\`${name} with id \${id} not found\`);
}
await collection.deleteOne({ _id: new ObjectId(id) });
return {
success: true,
message: "${name} deleted successfully",
data: new ${name}(doc) as ${pluralName}
};
} catch (error) {
console.error("Error deleting ${name.toLowerCase()}:", error);
throw error;
}
};
}
// ! -- CUSTOM METHODS --
// You can add custom methods or business logic below this line
// For example:
// export class Custom${name}Repository extends ${name}Repository {
// customMethod = async () => {
// // Your custom logic here
// }
// }
export const Repository = new ${name}Repository();`;
// src/generators/languages/typescript/templates/framework/next/schema/mongoose.ts
var generateMongooseSchema4 = (name, fields) => {
const mapTypeToMongoose = (zodType) => {
const typeMap = {
string: "String",
number: "Number",
boolean: "Boolean",
date: "Date",
array: "Array",
object: "Object"
};
return typeMap[zodType] || "String";
};
const mapTypeToZod = (type) => {
const typeMap = {
string: "z.string()",
number: "z.number()",
boolean: "z.boolean()",
date: "z.date()",
array: "z.array(z.any())",
object: "z.object({})"
};
return typeMap[type] || "z.string()";
};
return `import { z } from "zod";
import mongoose from "mongoose";
// Definisi schema mongoose
const ${name.toLowerCase()}Schema = new mongoose.Schema({
${fields.map((f) => `${f.name}: {
type: ${mapTypeToMongoose(f.type)},
required: true
}`).join(`,
`)}
}, {
timestamps: true
});
// Model mongoose
export const ${name} = mongoose.models.${name} || mongoose.model('${name}', ${name.toLowerCase()}Schema);
// Zod schema untuk validasi
const ${name}Schema = z.object({
${fields.map((f) => `${f.name}: ${mapTypeToZod(f.type)}`).join(`,
`)}
})
const TimestampSchema = z.object({
createdAt: z.date(),
updatedAt: z.date()
})
export const ${name}IdValidate = z.object({
id: z.string().refine((val) => mongoose.Types.ObjectId.isValid(val), {
message: "ID harus berupa ObjectId yang valid"
})
})
export const Create${name}Validate = ${name}Schema
export const ${pluralize(name)}Validate = ${name}Schema
.merge(z.object({
_id: z.instanceof(mongoose.Types.ObjectId).or(z.string())
}))
.merge(TimestampSchema)
export const Update${name}Validate = ${name}Schema.partial()
export type Create${name} = z.infer<typeof Create${name}Validate>
export type ${pluralize(name)} = z.infer<typeof ${pluralize(name)}Validate>
export type Update${name} = z.infer<typeof Update${name}Validate>
export type ${name}Id = z.infer<typeof ${name}IdValidate>
`;
};
// src/generators/languages/typescript/templates/framework/next/schema/mongodb.ts
var generateMongodbSchema4 = (name, fields) => `import { z } from "zod"
import { ObjectId } from "mongodb"
export class ${name} {
constructor(data: Partial<${pluralize(name)}>) {
Object.assign(this, data)
}
}
const ${name}Schema = z.object({
${fields.map((f) => `${f.name}: z.${f.type}()`).join(`,
`)}
})
const WithIdSchema = z.object({
_id: z.instanceof(ObjectId)
})
const TimestampSchema = z.object({
createdAt: z.date(),
updatedAt: z.date()
})
export const ${name}IdValidate = z.object({
id: z.string().regex(/^[0-9a-fA-F]{24}$/, "Invalid ObjectId format")
})
export const Create${name}Validate = ${name}Schema
export const ${pluralize(name)}Validate = ${name}Schema
.merge(WithIdSchema)
.merge(TimestampSchema)
export const Update${name}Validate = ${name}Schema.partial()
export type Create${name} = z.infer<typeof Create${name}Validate>
export type ${pluralize(name)} = z.infer<typeof ${pluralize(name)}Validate>
export type Update${name} = z.infer<typeof Update${name}Validate>
export type ${name}Id = z.infer<typeof ${name}IdValidate>
`;
// src/generators/languages/typescript/templates/framework/next/schema/sql.ts
var generateSqlSchema4 = (name, fields) => `import { z } from "zod"
export class ${name} {
constructor(data: Partial<${pluralize(name)}>) {
Object.assign(this, data)
}
}
const ${name}Schema = z.object({
${fields.map((f) => `${f.name}: z.${f.type}()`).join(`,
`)}
})
const WithIdSchema = z.object({
id: z.number()
})
const TimestampSchema = z.object({
createdAt: z.date(),
updatedAt: z.date()
})
export const ${name}IdValidate = z.object({
id: z.coerce.number().positive("ID harus positif")
})
export const Create${name}Validate = ${name}Schema
export const ${pluralize(name)}Validate = ${name}Schema
.merge(WithIdSchema)
.merge(TimestampSchema)
export const Update${name}Validate = ${name}Schema.partial()
export type Create${name} = z.infer<typeof Create${name}Validate>
export type ${pluralize(name)} = z.infer<typeof ${pluralize(name)}Validate>
export type Update${name} = z.infer<typeof Update${name}Validate>
export type ${name}Id = z.infer<typeof ${name}IdValidate>
`;
// src/generators/languages/typescript/templates/framework/next/service/mongoose.ts
var generateMongooseService4 = (name, pluralName) => `import { db } from '../../config';
import type { Create${name}, Update${name} } from './${name.toLowerCase()}.schema';
import { ${name}, Create${name}Validate, Update${name}Validate } from './${name.toLowerCase()}.schema';
import { NotFoundError, BadRequestError } from '../../error';
export class ${name}Service {
create = async (data: Create${name}) => {
try {
const validatedData = Create${name}Validate.parse(data);
const ${name.toLowerCase()} = new ${name}(validatedData);
const saved${name} = await ${name.toLowerCase()}.save();
return {
success: true,
message: "${name} created successfully",
data: saved${name}
};
} catch (error) {
console.error("Error creating ${name.toLowerCase()}:", error);
throw error;
}
};
getAll = async () => {
try {
const ${pluralName.toLowerCase()} = await ${name}.find();
return {
success: true,
data: ${pluralName.toLowerCase()}
};
} catch (error) {
console.error("Error getting all ${pluralName.toLowerCase()}:", error);
throw error;
}
};
getById = async (id: string) => {
try {
if (!db.Types.ObjectId.isValid(id)) {
throw new BadRequestError("Invalid ${name.toLowerCase()} ID");
}
const ${name.toLowerCase()} = await ${name}.findById(id);
if (!${name.toLowerCase()}) {
throw new NotFoundError("${name} not found");
}
return {
success: true,
data: ${name.toLowerCase()}
};
} catch (error) {
console.error(\`Error getting ${name.toLowerCase()} with ID \${id}:\`, error);
throw error;
}
};
update = async (id: string, data: Update${name}) => {
try {
if (!db.Types.ObjectId.isValid(id)) {
throw new BadRequestError("Invalid ${name.toLowerCase()} ID");
}
// Validasi data dengan Zod
const validatedData = Update${name}Validate.parse(data);
const updated${name} = await ${name}.findByIdAndUpdate(
id,
{ ...validatedData },
{ new: true }
);
if (!updated${name}) {
throw new NotFoundError("${name} not found");
}
return {
success: true,
message: "${name} updated successfully",
data: updated${name}
};
} catch (error) {
console.error(\`Error updating ${name.toLowerCase()} with ID \${id}:\`, error);
throw error;
}
};
delete = async (id: string) => {
try {
if (!db.Types.ObjectId.isValid(id)) {
throw new BadRequestError("Invalid ${name.toLowerCase()} ID");
}
const deleted${name} = await ${name}.findByIdAndDelete(id);
if (!deleted${name}) {
throw new NotFoundError("${name} not found");
}
return {
success: true,
message: "${name} deleted successfully",
data: deleted${name}
};
} catch (error) {
console.error(\`Error deleting ${name.toLowerCase()} with ID \${id}:\`, error);
throw error;
}
};
}
export const Service = new ${name}Service();
`;
// src/generators/languages/typescript/templates/framework/next/service/mongodb.ts
var generateMongodbService4 = (name, pluralName) => `import { Repository as ${name} } from "./${name.toLowerCase()}.repository";
import type { Create${name}, Update${name} } from "./${name.toLowerCase()}.schema";
import {
Create${name}Validate,
Update${name}Validate,
${name}IdValidate
} from "./${name.toLowerCase()}.schema";
export const Service = {
create: async (data: Create${name}) => {
try {
const validated = Create${name}Validate.parse(data);
return await ${name}.create(validated);
} catch (error) {
console.error("Service error creating ${name.toLowerCase()}:", error);
throw error;
}
},
getAll: async () => {
try {
return await ${name}.findAll();
} catch (error) {
console.error("Service error getting all ${pluralName.toLowerCase()}:", error);
throw error;
}
},
getById: async (id: string) => {
try {
const { id: validId } = ${name}IdValidate.parse({ id });
return await ${name}.findById({ id: validId });
} catch (error) {
console.error("Service error getting ${name.toLowerCase()} by id:", error);
throw error;
}
},
update: async (id: string, data: Update${name}) => {
try {
const { id: validId } = ${name}IdValidate.parse({ id });
const validated = Update${name}Validate.parse(data);
return await ${name}.update({ id: validId }, validated);
} catch (error) {
console.error("Service error updating ${name.toLowerCase()}:", error);
throw error;
}
},
delete: async (id: string) => {
try {
const { id: validId } = ${name}IdValidate.parse({ id });
return await ${name}.delete({ id: validId });
} catch (error) {
console.error("Service error deleting ${name.toLowerCase()}:", error);
throw error;
}
}
};`;
// src/generators/languages/typescript/templates/framework/next/service/sql.ts
var generateSqlService4 = (name, pluralName) => `import { Repository as ${name} } from "./${name.toLowerCase()}.repository";
import type { Create${name}, Update${name}, ${pluralName} } from "./${name.toLowerCase()}.schema";
import {
Create${name}Validate,
Update${name}Validate
} from "./${name.toLowerCase()}.schema";
import type { Result } from "./${name.toLowerCase()}.repository";
export const Service = {
create: async (data: Create${name}): Promise<Result<${pluralName}>> => {
try {
const validated = Create${name}Validate.parse(data);
return await ${name}.create(validated);
} catch (error) {
console.error("Service error creating ${name.toLowerCase()}:", error);
return {
success: false,
message: error instanceof Error ? error.message : "Failed to create ${name.toLowerCase()}",
data: null
};
}
},
getAll: async (): Promise<Result<${pluralName}[]>> => {
try {
return await ${name}.findAll();
} catch (error) {
console.error("Service error getting all ${pluralName.toLowerCase()}:", error);
return {
success: false,
message: error instanceof Error ? error.message : "Failed to get all ${pluralName.toLowerCase()}",
data: null
};
}
},
getById: async (id: string): Promise<Result<${pluralName}>> => {
try {
return await ${name}.findById({ id: Number(id) });
} catch (error) {
console.error("Service error getting ${name.toLowerCase()} by id:", error);
return {
success: false,
message: error instanceof Error ? error.message : "Failed to get ${name.toLowerCase()} by id",
data: null
};
}
},
update: async (id: string, data: Update${name}): Promise<Result<${pluralName}>> => {
try {
const validated = Update${name}Validate.parse(data);
return await ${name}.update({ id: Number(id) }, validated);
} catch (error) {
console.error("Service error updating ${name.toLowerCase()}:", error);
return {
success: false,
message: error instanceof Error ? error.message : "Failed to update ${name.toLowerCase()}",
data: null
};
}
},
delete: async (id: string): Promise<Result<${pluralName}>> => {
try {
return await ${name}.delete({ id: Number(id) });
} catch (error) {
console.error("Service error deleting ${name.toLowerCase()}:", error);
return {
success: false,
message: error instanceof Error ? error.message : "Failed to delete ${name.toLowerCase()}",
data: null
};
}
}
};`;
// src/generators/languages/typescript/templates/framework/next/controller.ts
var generateController4 = (name, pluralName) => ({
main: `import { Service as ${name} } from "../../../modules/${pluralName.toLowerCase()}/${name.toLowerCase()}.service";
import { NextResponse } from "next/server";
import { handleError } from "../../../error";
export async function GET() {
try {
const result = await ${name}.getAll();
return NextResponse.json(result);
} catch (error) {
return handleError(error);
}
}
export async function POST(req: Request) {
try {
const body = await req.json();
const result = await ${name}.create(body);
return NextResponse.json(result, { status: 201 });
} catch (error) {
return handleError(error);
}
}`,
dynamic: `import { Service as ${name} } from "../../../../modules/${pluralName.toLowerCase()}/${name.toLowerCase()}.service";
import { NextResponse } from "next/server";
import { handleError } from "../../../../error";
export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) {
try {
const { id } = await params;
const result = await ${name}.getById(id);
return NextResponse.json(result);
} catch (error) {
return handleError(error);
}
}
export async function PUT(req: Request, { params }: { params: Promise<{ id: string }> }) {
try {
const { id } = await params;
const body = await req.json();
const result = await ${name}.update(id, body);
return NextResponse.json(result);
} catch (error) {
return handleError(error);
}
}
export async function DELETE(_req: Request, { params }: { params: Promise<{ id: string }> }) {
try {
const { id } = await params;
const result = await ${name}.delete(id);
return NextResponse.json(result);
} catch (error) {
return handleError(error);
}
}`
});
// src/generators/languages/typescript/templates/framework/next/error.ts
var generateError4 = () => `import { NextResponse } from 'next/server';
import { ZodError } from 'zod';
// Kelas error kustom dengan status code
export class HttpError extends Error {
statusCode: number;
constructor(message: string, statusCode: number) {
super(message);
this.statusCode = statusCode;
this.name = this.constructor.name;
// Untuk mendapatkan stack trace yang benar
Error.captureStackTrace(this, this.constructor);
}
}
// Error untuk resource tidak ditemukan (404)
export class NotFoundError extends HttpError {
constructor(message: string = 'Resource not found') {
super(message, 404);
}
}
// Error untuk permintaan yang tidak valid (400)
export class BadRequestError extends HttpError {
constructor(message: string = 'Bad request') {
super(message, 400);
}
}
// Error untuk validasi gagal (422)
export class ValidationError extends HttpError {
constructor(message: string = 'Validation failed') {
super(message, 422);
}
}
// Error untuk autentikasi gagal (401)
export class UnauthorizedError extends HttpError {
constructor(message: string = 'Unauthorized access') {
super(message, 401);
}
}
// Error untuk akses terlarang (403)
export class ForbiddenError extends HttpError {
constructor(message: string = 'Access forbidden') {
super(message, 403);
}
}
// Error untuk konflik data (409)
export class ConflictError extends HttpError {
constructor(message: string = 'Resource conflict') {
super(message, 409);
}
}
// Fungsi untuk membuat respons error
export const createErrorResponse = (
message: string,
statusCode: number = 500,
errors?: Record<string, unknown>
) => {
return NextResponse.json({
success: false,
message,
...(errors && { errors })
}, { status: statusCode });
};
// Fungsi untuk menangani error
export const handleError = (error: unknown): NextResponse => {
console.error('Error caught by error handler:', error);
// HttpError kustom
if (error instanceof HttpError) {
return createErrorResponse(error.message, error.statusCode);
}
// Zod validation errors
if (error instanceof ZodError) {
const formattedErrors = error.errors.map(err => ({
path: err.path.join('.'),
message: err.message
}));
return createErrorResponse('Validation failed', 422, { details: formattedErrors });
}
// Error MongoDB duplicate key
if (error instanceof Error && error.message.includes('duplicate key error')) {
return createErrorResponse('Duplicate entry found', 409);
}
// Error MongoDB validation
if (error instanceof Error && error.name === 'ValidationError') {
return createErrorResponse('Database validation failed', 422);
}
// Error MongoDB cast
if (error instanceof Error && error.name === 'CastError') {
return createErrorResponse('Invalid data format', 400);
}
// Generic errors
if (error instanceof Error) {
// Jika error memiliki pesan yang jelas, gunakan itu
const message = error.message || 'Something went wrong';
return createErrorResponse(message, 500);
}
// Unknown errors
return createErrorResponse('An unexpected error occurred', 500);
};`;
// src/generators/languages/typescript/templates/database/postgresql/migration.ts
var generatePostgresMigration = (name, pluralName, fields) => {
const pgTypes = {
string: "VARCHAR(255)",
number: "INTEGER",
boolean: "BOOLEAN",
date: "TIMESTAMP"
};
const columns = fields.map((field) => {
const pgType = pgTypes[field.type] || "VARCHAR(255)";
return ` "${field.name}" ${pgType}`;
}).join(`,
`);
return `import { sql } from "../../config";
export async function up() {
await sql\`
CREATE TABLE IF NOT EXISTS ${pluralName.toLowerCase()} (
id SERIAL PRIMARY KEY,
${columns},
"createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
\`.simple();
console.log('\u2705 Migration ${name} created successfully');
}
export async function down() {
await sql\`DROP TABLE IF EXISTS ${pluralName.toLowerCase()}\`.simple();
console.log('\u2705 Migration ${name} dropped successfully');
}
// Run migration
if (process.argv[2] === 'up') {
up().catch(console.error).finally(() => process.exit());
}
if (process.argv[2] === 'down') {
down().catch(console.error).finally(() => process.exit());
}`;
};
// src/generators/languages/typescript/templates/database/mariadb/migration.ts
var generateMariadbMigration = (name, pluralName, fields) => {
const mariaTypes = {
string: "VARCHAR(255)",
number: "INT",
boolean: "TINYINT(1)",
date: "DATETIME"
};
const columns = fields.map((field) => {
const mariaType = mariaTypes[field.type] || "VARCHAR(255)";
return ` ${field.name} ${mariaType}`;
}).join(`,
`);
return `import { db } from "../../config";
export async function up() {
await db.query(\`
CREATE TABLE IF NOT EXISTS ${pluralName.toLowerCase()} (
id INT AUTO_INCREMENT PRIMARY KEY,
${columns},
createdAt DATETIME DEFAULT CURRENT_TIMESTAMP,
updatedAt DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)
\`);
console.log('\u2705 Migration ${name} created successfully');
}
export async function down() {
await db.query(\`
DROP TABLE IF EXISTS ${pluralName.toLowerCase()}
\`);
console.log('\u2705 Migration ${name} dropped successfully');
}
// Run migration
if (process.argv[2] === 'up') {
up()
.catch(console.error)
.finally(() => process.exit());
}
if (process.argv[2] === 'down') {
down()
.catch(console.error)
.finally(() => process.exit());
}`;
};
// src/generators/languages/typescript/templates/database/sqlite/migration.ts
var generateSqliteMigration = (name, pluralName, fields) => {
const sqliteTypes = {
string: "TEXT",
number: "INTEGER",
boolean: "INTEGER",
date: "TEXT"
};
const columns = fields.map((field) => {
const sqliteType = sqliteTypes[field.type] || "TEXT";
return ` ${field.name} ${sqliteType}`;
}).join(`,
`);
return `import { db } from "../../config";
export async function up() {
db.query(\`
CREATE TABLE IF NOT EXISTS ${pluralName.toLowerCase()} (
id INTEGER PRIMARY KEY AUTOINCREMENT,
${columns},
createdAt TEXT DEFAULT (datetime('now')),
updatedAt TEXT DEFAULT (datetime('now'))
);
\`).run();
console.log('\u2705 Migration ${name} created successfully');
}
export async function down() {
db.query(\`
DROP TABLE IF EXISTS ${pluralName.toLowerCase()}
\`).run();
console.log('\u2705 Migration ${name} dropped successfully');
}
// Run migration
if (process.argv[2] === 'up') {
up()
.catch(console.error)
.finally(() => process.exit());
}
if (process.argv[2] === 'down') {
down()
.catch(console.error)
.finally(() => process.exit());
}`;
};
// src/generators/languages/typescript/templates/database/postgresql/seeding.ts
var generatePostgresSeeding = (name, pluralName, fields) => {
return `import { sql } from "../../config";
import sampleData from "../../data/${pluralName.toLowerCase()}.json";
export async function seed() {
// Gunakan fitur bulk insert dari Bun SQL
await sql\`INSERT INTO ${pluralName.toLowerCase()} \${sql(sampleData)}\`;
console.log('\u2705 Seeding ${name} completed successfully');
}
export async function unseed() {
await sql\`TRUNCATE TABLE ${pluralName.toLowerCase()} RESTART IDENTITY\`.simple();
console.log('\u2705 Unseeding ${name} completed successfully');
}
// Run seeding
if (process.argv[2] === 'seed') {
seed().catch(console.error).finally(() => process.exit());
}
if (process.argv[2] === 'unseed') {
unseed().catch(console.error).finally(() => process.exit());
}`;
};
// src/generators/languages/typescript/templates/database/mariadb/seeding.ts
var generateMariadbSeeding = (name, pluralName, fields) => {
return `import { db } from "../../config";
import sampleData from "../../data/${pluralName.toLowerCase()}.json";
export async function seed() {
const values = sampleData
.map(data => {
const fieldValues = [
${fields.map((f) => `data.${f.name}`).join(`,
`)}
];
return \` (\${fieldValues.map(v => typeof v === 'string' ? \`'\${v}'\` : v).join(', ')}, NOW(), NOW())\`;
})
.join(',\\n');
await db.query(\`
INSERT INTO ${pluralName.toLowerCase()} (
${fields.map((f) => f.name).join(", ")},
createdAt,
updatedAt
) VALUES
\${values}
\`);
console.log('\u2705 Seeding ${name} completed successfully');
}
export async function unseed() {
await db.query(\`
TRUNCATE TABLE ${pluralName.toLowerCase()}
\`);
console.log('\u2705 Unseeding ${name} completed successfully');
}
// Run seeding
if (process.argv[2] === 'seed') {
seed()
.catch(console.error)
.finally(() => process.exit());
}
if (process.argv[2] === 'unseed') {
unseed()
.catch(console.error)
.finally(() => process.exit());
}`;
};
// src/generators/languages/typescript/templates/database/sqlite/seeding.ts
var generateSqliteSeeding = (name, pluralName, fields) => {
return `import { db } from "../../config";
import sampleData from "../../data/${pluralName.toLowerCase()}.json";
export async function seed() {
const values = sampleData
.map(data => {
const fieldValues = [
${fields.map((f) => `data.${f.name}`).join(`,
`)}
];
return \` (\${fieldValues.map(v => typeof v === 'string' ? \`'\${v}'\` : v).join(', ')}, datetime('now'), datetime('now'))\`;
})
.join(',\\n');
db.query(\`
INSERT INTO ${pluralName.toLowerCase()} (
${fields.map((f) => f.name).join(", ")},
createdAt,
updatedAt
) VALUES
\${values}
\`).run();
console.log('\u2705 Seeding ${name} completed successfully');
}
export async function unseed() {
db.query(\`
DELETE FROM ${pluralName.toLowerCase()};
DELETE FROM sqlite_sequence WHERE name = '${pluralName.toLowerCase()}';
\`).run();
console.log('\u2705 Unseeding ${name} completed successfully');
}
// Run seeding
if (process.argv[2] === 'seed') {
seed()
.catch(console.error)
.finally(() => process.exit());
}
if (process.argv[2] === 'unseed') {
unseed()
.catch(console.error)
.finally(() => process.exit());
}`;
};
// src/generators/languages/typescript/templates/database/mongodb/seeding.ts
var generateMongoSeeding = (name, pluralName) => `import { db, client } from "../../config";
import { ObjectId } from "mongodb";
import sampleData from "../../data/${pluralName.toLowerCase()}.json";
const seed = async () => {
try {
const collection = db.collection("${pluralName.toLowerCase()}");
await collection.insertMany(
sampleData.map(data => ({
_id: new ObjectId(),
...data,
createdAt: new Date(),
updatedAt: new Date()
}))
);
console.log('\u2705 Seeding ${name} completed successfully');
} catch (error) {
console.error('\u274C Seeding failed:', error);
} finally {
await client.close();
}
};
const unseed = async () => {
try {
await db.collection("${pluralName.toLowerCase()}").deleteMany({});
console.log('\u2705 Unseeding ${name} completed successfully');
} catch (error) {
console.error('\u274C Unseeding failed:', error);
} finally {
await client.close();
}
};
// Run seeding
if (process.argv[2] === 'seed') {
seed()
.catch(console.error)
.finally(() => process.exit());
}
if (process.argv[2] === 'unseed') {
unseed()
.catch(console.error)
.finally(() => process.exit());
}
export { seed, unseed };`;
var generateMongooseSeeding = (name, pluralName) => `import { db } from "../../config";
import { ${name} } from "./${name.toLowerCase()}.schema";
import sampleData from "../../data/${pluralName.toLowerCase()}.json";
export async function seed() {
try {
// Transform data dari json ke format MongoDB
const values = sampleData.map(data => ({
...data,
// Mongoose akan otomatis generate ObjectId
createdAt: new Date(),
updatedAt: new Date()
}));
// Gunakan model mongoose untuk insert data
await ${name}.insertMany(values);
console.log('\u2705 Seeding ${name} completed successfully');
} catch (error) {
console.error('\u274C Seeding failed:', error);
throw error;
}
}
export async function unseed() {
try {
// Gunakan model mongoose untuk delete data
await ${name}.deleteMany({});
console.log('\u2705 Unseeding ${name} completed successfully');
} catch (error) {
console.error('\u274C Unseeding failed:', error);
throw error;
}
}
// Run seeding
if (process.argv[2] === 'seed') {
seed()
.catch(console.error)
.finally(() => {
db.disconnect();
process.exit();
});
}
if (process.argv[2] === 'unseed') {
unseed()
.catch(console.error)
.finally(() => {
db.disconnect();
process.exit();
});
}`;
// src/generators/languages/typescript/templates/database/postgresql/config.ts
var generatePostgresConfig = () => `import { SQL } from 'bun';
import config from './db.json';
const env = process.env.NODE_ENV || 'development';
const dbConfig = config[env as keyof typeof config];
export const sql = new SQL({
hostname: dbConfig.host,
port: dbConfig.port,
username: dbConfig.username,
password: dbConfig.password,
database: dbConfig.database
});
sql\`SELECT 1\`.then(() => console.log(\`\u2705 PostgreSQL connected (\${env})\`))
.catch(e => { console.error('\u274C DB connection failed:', e); process.exit(1); });
export default sql;`;
// src/generators/languages/typescript/templates/database/mariadb/config.ts
var generateMariadbConfig = () => `import mariadb from 'mariadb';
import config from './db.json';
const env = process.env.NODE_ENV || 'development';
const dbConfig = config[env as keyof typeof config];
type SqlValue = string | number | boolean | null | Date | Buffer;
// Create connection pool
const pool = mariadb.createPool({
host: dbConfig.host,
port: dbConfig.port,
user: dbConfig.username,
password: dbConfig.password,
database: dbConfig.database
});
// Wrapper utk query database
export const db = {
query: async (sql: string, values?: SqlValue[]) => {
let conn;
try {
conn = await pool.getConnection();
const result = await conn.query(sql, values);
return result;
} catch (error) {
console.error('Database Error:', error);
throw error;
} finally {
if (conn) conn.release();
}
}
};
// Helper utk cek koneksi
export const testConnection = async () => {
let conn;
try {
conn = await pool.getConnection();
console.log('\u2705 MariaDB connection successful!');
return true;
} catch (error) {
console.error('\u274C MariaDB connection failed:', error);
return false;
} finally {
if (conn) conn.release();
}
};
export default pool;`;
// src/generators/languages/typescript/templates/database/sqlite/config.ts
var generateSqliteConfig = () => `import { Database } from 'bun:sqlite';
import config from './db.json';
const env = process.env.NODE_ENV || 'development';
const { database } = config[env as keyof typeof config];
export const db = new Database(database);
try {
db.query('SELECT 1').get();
console.log(\`\u2705 SQLite connected (\${env})\`);
} catch (error) {
console.error('\u274C SQLite connection failed:', error);
process.exit(1);
}
export default db;`;
// src/generators/languages/typescript/templates/database/mongodb/config.ts
var generateMongoConfig = () => `import { MongoClient, Db } from 'mongodb';
import config from './db.json';
const env = process.env.NODE_ENV || 'development';
const { url, database } = config[env as keyof typeof config];
export let db: Db;
export let client: MongoClient;
try {
client = await MongoClient.connect(url);
db = client.db(database);
console.log('\u2705 MongoDB connected successfully!');
} catch (error) {
console.error('\u274C MongoDB connection failed:', error);
process.exit(1);
}`;
var generateMongooseConfig = () => `import mongoose from 'mongoose';
import config from './db.json';
const env = process.env.NODE_ENV || 'development';
const { url, database } = config[env as keyof typeof config];
// Connect ke MongoDB dan langsung export instance mongoose
try {
// Hapus trailing slash jika ada di akhir URL
const cleanUrl = url.endsWith('/') ? url.slice(0, -1) : url;
const connectionString = \`\${cleanUrl}/\${database}\`;
mongoose.connect(connectionString);
console.log('\u2705 MongoDB connected successfully!');
} catch (error) {
console.error('\u274C MongoDB connection failed:', error);
process.exit(1);
}
// Export mongoose instance untuk digunakan di seluruh aplikasi
export const db = mongoose;`;
// src/generators/languages/typescript/templates/database/postgresql/config-json.ts
var generatePostgresConfigJson = () => `{
"development": {
"username": "postgres",
"password": "postgres",
"database": "postgres-dev",
"host": "localhost",
"port": 5432
},
"test": {
"username": "postgres",
"password": "postgres",
"database": "postgres-test",
"host": "localhost",
"port": 5432
},
"production": {
"username": "postgres",
"password": "postgres",
"database": "postgres-prod",
"host": "localhost",
"port": 5432
}
}`;
// src/generators/languages/typescript/templates/database/mariadb/config-json.ts
var generateMariadbConfigJson = () => `{
"development": {
"host": "localhost",
"port": 3306,
"username": "root",
"password": "",
"database": "my_database"
},
"test": {
"host": "localhost",
"port": 3306,
"username": "root",
"password": "",
"database": "my_database_test"
},
"production": {
"host": "localhost",
"port": 3306,
"username": "root",
"password": "",
"database": "my_database_prod"
}
}`;
// src/generators/languages/typescript/templates/database/sqlite/config-json.ts
var generateSqliteConfigJson = () => `{
"development": {
"database": "./database.sqlite"
},
"test": {
"database": "./database.test.sqlite"
},
"production": {
"database": "./database.prod.sqlite"
}
}`;
// src/generators/languages/typescript/templates/database/mongodb/config-json.ts
var generateMongoConfigJson = () => `{
"development": {
"url": "mongodb://localhost:27017",
"database": "my_database"
},
"test": {
"url": "mongodb://localhost:27017",
"database": "my_database_test"
},
"production": {
"url": "mongodb://localhost:27017",
"database": "my_database_prod"
}
}`;
// src/generators/languages/typescript/src/mapping.ts
var configGenerators = {
mongodb: {
config: (mongoDriver = "mongoose") => mongoDriver === "mongoose" ? generateMongooseConfig() : generateMongoConfig(),
configJson: generateMongoConfigJson
},
postgresql: {
config: () => generatePostgresConfig(),
configJson: generatePostgresConfigJson
},
mariadb: {
config: () => generateMariadbConfig(),
configJson: generateMariadbConfigJson
},
sqlite: {
config: () => generateSqliteConfig(),
configJson: generateSqliteConfigJson
}
};
var repoGenerators = {
express: {
mongodb: generateMongoRepository,
postgresql: generatePostgresRepository,
mariadb: generateMariadbRepository,
sqlite: generateSqliteRepository
},
elysia: {
mongodb: generateMongoRepository2,
postgresql: generatePostgresRepository2,
mariadb: generateMariadbRepository2,
sqlite: generateSqliteRepository2
},
hono: {
mongodb: generateMongoRepository3,
postgresql: generatePostgresRepository3,
mariadb: generateMariadbRepository3,
sqlite: generateSqliteRepository3
},
next: {
mongodb: generateMongoRepository4,
postgresql: generatePostgresRepository4,
mariadb: generateMariadbRepository4,
sqlite: generateSqliteRepository4
}
};
var dbGenerators = {
mongodb: {
seed: (name, pluralName, mongoDriver) => {
if (typeof mongoDriver === "string") {
return mongoDriver === "mongoose" ? generateMongooseSeeding(name, pluralName) : generateMongoSeeding(name, pluralName);
}
return generateMongoSeeding(name, pluralName);
}
},
postgresql: {
migrate: generatePostgresMigration,
seed: generatePostgresSeeding
},
mariadb: {
migrate: generateMariadbMigration,
seed: generateMariadbSeeding
},
sqlite: {
migrate: generateSqliteMigration,
seed: generateSqliteSeeding
}
};
var serviceGenerators = {
express: {
sql: generateSqlService,
mongodb: generateMongodbService,
mongoose: generateMongooseService
},
elysia: {
sql: generateSqlService2,
mongodb: generateMongodbService2,
mongoose: generateMongooseService2
},
hono: {
sql: generateSqlService3,
mongodb: generateMongodbService3,
mongoose: generateMongooseService3
},
next: {
sql: generateSqlService4,
mongodb: generateMongodbService4,
mongoose: generateMongooseService4
}
};
var controllerGenerators = {
express: generateController,
elysia: generateController2,
hono: generateController3,
next: generateController4
};
var serverGenerators = {
express: generateServer,
elysia: generateServer2,
hono: generateServer3
};
var errorGenerators = {
express: generateError,
elysia: generateError2,
hono: generateError3,
next: generateError4
};
var getSchemaGenerator = (framework, isNoSql, mongoDriver) => {
if (isNoSql) {
if (framework === "express") {
return mongoDriver === "mongoose" ? generateMongooseSchema : generateMongodbSchema;
}
if (framework === "hono") {
return mongoDriver === "mongoose" ? generateMongooseSchema3 : generateMongodbSchema3;
}
if (framework === "elysia") {
return mongoDriver === "mongoose" ? generateMongooseSchema2 : generateMongodbSchema2;
}
if (framework === "next") {
return mongoDriver === "mongoose" ? generateMongooseSchema4 : generateMongodbSchema4;
}
}
const generators = {
express: isNoSql ? generateMongodbSchema : generateSqlSchema,
elysia: isNoSql ? generateMongodbSchema2 : generateSqlSchema2,
hono: isNoSql ? generateMongodbSchema3 : generateSqlSchema3,
next: isNoSql ? generateMongodbSchema4 : generateSqlSchema4
};
return generators[framework];
};
var getServiceGenerator = (framework, isNoSql, mongoDriver) => {
if (framework === "express") {
if (isNoSql) {
return mongoDriver === "mongoose" ? serviceGenerators.express.mongoose : serviceGenerators.express.mongodb;
}
return serviceGenerators.express.sql;
}
if (framework === "hono") {
if (isNoSql) {
return mongoDriver === "mongoose" ? serviceGenerators.hono.mongoose : serviceGenerators.hono.mongodb;
}
return serviceGenerators.hono.sql;
}
if (framework === "elysia") {
if (isNoSql) {
return mongoDriver === "mongoose" ? serviceGenerators.elysia.mongoose : serviceGenerators.elysia.mongodb;
}
return serviceGenerators.elysia.sql;
}
if (framework === "next") {
if (isNoSql) {
return mongoDriver === "mongoose" ? serviceGenerators.next.mongoose : serviceGenerators.next.mongodb;
}
return serviceGenerators.next.sql;
}
throw new Error(`Service generator untuk framework ${framework} tidak ditemukan`);
};
// src/generators/languages/typescript/src/index.ts
async function generateCrud(name, fields, config) {
const { framework, database, projectDir, mongoDriver = "mongoose" } = config;
const isNoSql = database === "mongodb";
const cwd = process.cwd();
console.log(source_default.blue("\uD83D\uDCE6 Detail Generate:"));
console.log(source_default.yellow(`Framework: ${framework}`));
console.log(source_default.yellow(`Database: ${database}`));
if (database === "mongodb") {
console.log(source_default.yellow(`MongoDB Driver: ${mongoDriver}`));
}
console.log(source_default.yellow(`Model: ${name}`));
console.log(source_default.yellow(`Project Directory: ${projectDir || "root"}`));
console.log(source_default.yellow("Fields:"));
fields.forEach((field) => {
console.log(source_default.yellow(` - ${field.name}: ${field.type}`));
});
const configDir = `${cwd}/${projectDir ? projectDir + "/" : ""}config`;
await Bun.spawn(["mkdir", "-p", configDir]).exited;
const { config: configGenerator, configJson: configJsonGenerator } = configGenerators[database];
if (!configGenerator || !configJsonGenerator) {
throw new Error(`Database ${database} blm didukung`);
}
await Bun.write(`${configDir}/db.json`, configJsonGenerator());
console.log(source_default.green("Created db.json"));
await Bun.write(`${configDir}/index.ts`, configGenerator(mongoDriver));
console.log(source_default.green("Created config/index.ts"));
const structure = exports_constants[`${framework}Structure`];
const modulePath = `${cwd}/${structure.getModulesPath(projectDir || "")}`;
const moduleDir = `${modulePath}/${pluralize(name.toLowerCase())}`;
await Bun.spawn(["mkdir", "-p", moduleDir]).exited;
const schemaGenerator = getSchemaGenerator(framework, isNoSql, mongoDriver);
if (!schemaGenerator) {
throw new Error(`Framework ${framework} blm didukung`);
}
await Bun.write(`${moduleDir}/${name.toLowerCase()}.schema.ts`, schemaGenerator(name, fields));
console.log(source_default.green(`Created ${name.toLowerCase()}.schema.ts`));
const skipRepository = isNoSql && mongoDriver === "mongoose";
if (!skipRepository) {
const repoGenerator = repoGenerators[framework]?.[database];
if (!repoGenerator) {
throw new Error(`Database ${database} atau framework ${framework} blm didukung`);
}
await Bun.write(`${moduleDir}/${name.toLowerCase()}.repository.ts`, repoGenerator(name, pluralize(name)));
console.log(source_default.green(`Created ${name.toLowerCase()}.repository.ts`));
} else {
console.log(source_default.yellow(`Skipping repository generation for mongoose (not needed)`));
}
const dbGenerator = dbGenerators[database];
if (dbGenerator) {
if (dbGenerator?.migrate) {
await Bun.write(`${moduleDir}/${name.toLowerCase()}.migrate.ts`, dbGenerator.migrate(name, pluralize(name), fields));
console.log(source_default.green(`Created ${name.toLowerCase()}.migrate.ts`));
}
if (dbGenerator?.seed) {
if (database === "mongodb") {
await Bun.write(`${moduleDir}/${name.toLowerCase()}.seed.ts`, dbGenerator.seed(name, pluralize(name), mongoDriver));
} else {
await Bun.write(`${moduleDir}/${name.toLowerCase()}.seed.ts`, dbGenerator.seed(name, pluralize(name), fields));
}
console.log(source_default.green(`Created ${name.toLowerCase()}.seed.ts`));
}
}
const serviceGenerator = getServiceGenerator(framework, isNoSql, mongoDriver);
if (serviceGenerator) {
await Bun.write(`${moduleDir}/${name.toLowerCase()}.service.ts`, serviceGenerator(name, pluralize(name)));
console.log(source_default.green(`Created ${name.toLowerCase()}.service.ts`));
}
const controllerGenerator = controllerGenerators[framework];
if (controllerGenerator) {
if (framework === "next") {
const apiDir = `${cwd}/${projectDir ? projectDir + "/" : ""}app/api/${pluralize(name.toLowerCase())}`;
await Bun.spawn(["mkdir", "-p", `${apiDir}/[id]`]).exited;
const controllers = controllerGenerator(name, pluralize(name));
await Bun.write(`${apiDir}/route.ts`, controllers.main);
console.log(source_default.green(`Created route.ts in ${apiDir}`));
await Bun.write(`${apiDir}/[id]/route.ts`, controllers.dynamic);
console.log(source_default.green(`Created route.ts in ${apiDir}/[id]`));
} else {
await Bun.write(`${moduleDir}/index.ts`, controllerGenerator(name, pluralize(name)));
console.log(source_default.green(`Created index.ts with controller`));
}
}
try {
await updateRouter(name, framework, projectDir);
console.log(source_default.green(`Updated router.ts with new routes`));
} catch (error) {
console.error(source_default.red(`Failed to update router.ts: ${error.message}`));
}
const dataDir = `${cwd}/${projectDir ? projectDir + "/" : ""}data`;
await Bun.spawn(["mkdir", "-p", dataDir]).exited;
await Bun.write(`${dataDir}/${pluralize(name.toLowerCase())}.json`, generateJSONData(name, fields));
console.log(source_default.green(`Created ${pluralize(name.toLowerCase())}.json with sample data`));
const serverGenerator = serverGenerators[framework];
const indexPath = `${cwd}/${projectDir ? projectDir + "/" : ""}index.ts`;
if (serverGenerator) {
try {
await Bun.write(indexPath, serverGenerator());
console.log(source_default.green(`Updated index.ts with ${framework} server setup`));
} catch (error) {
console.error(source_default.red(`Failed to update index.ts: ${error.message}`));
}
}
const errorGenerator = errorGenerators[framework];
if (errorGenerator) {
try {
await Bun.write(`${cwd}/${projectDir ? projectDir + "/" : ""}error.ts`, errorGenerator());
console.log(source_default.green(`Created error.ts with error handler`));
} catch (error) {
console.error(source_default.red(`Failed to create error.ts: ${error.message}`));
}
}
console.log(source_default.green(`
\u2728 Files generated successfully!`));
}
// src/generators/utils/package.ts
import { readFile, writeFile as writeFile6 } from "fs/promises";
import { join as join7 } from "path";
async function updatePackageJson() {
try {
const packagePath = join7(process.cwd(), "package.json");
const content = await readFile(packagePath, "utf-8");
const pkg = JSON.parse(content);
pkg.scripts = {
...pkg.scripts,
dev: "henotic dev",
start: "henotic start",
build: "henotic build"
};
pkg.main = "dist/index.js";
await writeFile6(packagePath, JSON.stringify(pkg, null, 2));
console.log(source_default.green("\u2728 Package.json berhasil diupdate!"));
} catch (error) {
throw new Error("Gagal update package.json: " + error.message);
}
}
// src/generators/languages/typescript/index.ts
async function generateCommand(name, fields) {
try {
console.log(source_default.cyan(`
\uD83D\uDE80 Memulai generate CRUD...
`));
const config = await readConfig();
const parsedFields = parseFields(fields);
await generateCrud(name, parsedFields, config);
await updatePackageJson();
console.log(source_default.green(`
\u2728 Generate CRUD berhasil!
`));
} catch (error) {
const errMsg = error instanceof Error ? source_default.red(error.message) : "Unknown error occurred";
console.error(source_default.red(`
\u274C Aduh error nih: ${errMsg}
`));
process.exit(1);
}
}
// src/generators/languages/go/src/index.ts
import path4 from "path";
// src/generators/languages/go/src/seed.ts
import { access } from "fs/promises";
async function fileExists(path4) {
try {
await access(path4);
return true;
} catch {
return false;
}
}
async function updateSeedMain(name, projectDir = "", isFirstGenerate = false) {
try {
if (isFirstGenerate) {
return;
}
const cwd = process.cwd();
const pluralName = pluralize(name);
const seedMainPath = `${cwd}/${projectDir ? projectDir + "/" : ""}cmd/seed/main.go`;
if (!await fileExists(seedMainPath)) {
console.log(source_default.yellow("\u26A0\uFE0F File seed/main.go tidak ditemukan, skip update..."));
return;
}
let content = await Bun.file(seedMainPath).text();
if (content.includes(`seed.${pluralName}`)) {
return;
}
const importSection = content.match(/import \(([\s\S]*?)\)/)?.[0] || "";
const newImport = `${name.toLowerCase()}Entity "project-name/internal/module/${name.toLowerCase()}/entity"`;
if (!importSection.includes(newImport)) {
content = content.replace(/import \(([\s\S]*?)\)/, `import (
${newImport}$1)`);
}
const migrationsSection = content.match(/migrations := \[\]interface{}{([\s\S]*?)}/)?.[0] || "";
const newMigration = `&${name.toLowerCase()}Entity.${name}{}`;
if (!migrationsSection.includes(newMigration)) {
content = content.replace(/migrations := \[\]interface{}{([\s\S]*?)}/, `migrations := []interface{}{
${newMigration},$1}`);
}
const seedsSection = content.match(/seeds := \[\]struct {([\s\S]*?)}{([\s\S]*?)}/)?.[0] || "";
const newSeed = `{"${name.toLowerCase()}", seed.${pluralName}}`;
if (!seedsSection.includes(newSeed)) {
content = content.replace(/seeds := \[\]struct {([\s\S]*?)}{([\s\S]*?)}/, `seeds := []struct {$1}{
${newSeed},$2}`);
}
await Bun.write(seedMainPath, content);
console.log(source_default.green(`\u2705 Updated seed/main.go dengan seed untuk ${name}`));
} catch (error) {
console.error(source_default.red(`\u274C Error updating seed/main.go: ${error.message}`));
}
}
// src/generators/languages/go/src/main.ts
import { readdir, access as access2 } from "fs/promises";
import { join as join8 } from "path";
async function fileExists2(path4) {
try {
await access2(path4);
return true;
} catch {
return false;
}
}
async function updateMainGo(name, projectDir = "", isFirstGenerate = false) {
try {
if (isFirstGenerate) {
return;
}
const cwd = process.cwd();
const lowerName = name.toLowerCase();
const mainPath = `${cwd}/${projectDir ? projectDir + "/" : ""}cmd/main/main.go`;
if (!await fileExists2(mainPath)) {
console.log(source_default.yellow("\u26A0\uFE0F File main.go tidak ditemukan, skip update..."));
return;
}
let content = await Bun.file(mainPath).text();
const importRegex = new RegExp(`"project-name/internal/module/${lowerName}"`, "g");
if (importRegex.test(content)) {
return;
}
const importSection = content.match(/import \(\n([\s\S]*?)\)/)?.[0] || "";
if (!importSection) {
console.log(source_default.yellow("\u26A0\uFE0F Format main.go tidak sesuai, skip update import..."));
return;
}
const newImportSection = importSection.replace(/import \(\n([\s\S]*?)\)/, `import (
$1 "project-name/internal/module/${lowerName}"
)`);
content = content.replace(importSection, newImportSection);
const initRegex = new RegExp(`${lowerName}\\.Initialize\\(db, api\\)`, "g");
if (initRegex.test(content)) {
return;
}
const lastInitIndex = content.lastIndexOf(".Initialize(db, api)");
if (lastInitIndex === -1) {
console.log(source_default.yellow("\u26A0\uFE0F Format main.go tidak sesuai, skip update inisialisasi..."));
return;
}
const lastInitLine = content.substring(0, lastInitIndex).split(`
`).pop() + ".Initialize(db, api)";
content = content.replace(lastInitLine, `${lastInitLine}
${lowerName}.Initialize(db, api)`);
await Bun.write(mainPath, content);
console.log(source_default.green(`\u2705 Updated main.go dengan modul ${name}`));
} catch (error) {
console.error(source_default.red(`\u274C Error updating main.go: ${error.message}`));
}
}
async function getExistingModules(projectDir = "") {
try {
const cwd = process.cwd();
const modulesPath = join8(cwd, projectDir, "internal/module");
if (!await fileExists2(modulesPath)) {
return [];
}
const modules = await readdir(modulesPath);
return modules.map((module) => {
const pascalCase = module.charAt(0).toUpperCase() + module.slice(1);
return {
name: pascalCase,
lowerName: module
};
});
} catch (error) {
console.error(source_default.red(`\u274C Error getting existing modules: ${error}`));
return [];
}
}
// src/generators/languages/go/templates/database/mariadb/config.ts
var generateGoMariadbConfig = () => `package config
import (
"log"
"os"
"github.com/joho/godotenv"
)
type Config struct {
DBHost string
DBPort string
DBUser string
DBPassword string
DBName string
ServerPort string
Environment string
TrustedProxies string
}
func LoadConfig() *Config {
err := godotenv.Load()
if err != nil {
log.Println("Warning: .env file not found, using default values")
}
return &Config{
DBHost: getEnv("DB_HOST", "localhost"),
DBPort: getEnv("DB_PORT", "3306"),
DBUser: getEnv("DB_USER", "root"),
DBPassword: getEnv("DB_PASSWORD", "password"),
DBName: getEnv("DB_NAME", "mariadb"),
ServerPort: getEnv("SERVER_PORT", "8080"),
Environment: getEnv("APP_ENV", "development"),
TrustedProxies: getEnv("TRUSTED_PROXIES", "127.0.0.1"),
}
}
func getEnv(key, fallback string) string {
if value, exists := os.LookupEnv(key); exists {
return value
}
return fallback
}
`;
// src/generators/languages/go/templates/database/mariadb/database.ts
var generateGoMariadbDatabase = () => `package database
import (
"fmt"
"log"
"project-name/pkg/config"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
func Connect() *gorm.DB {
// Load config
cfg := config.LoadConfig()
// Connect to MariaDB
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
cfg.DBUser,
cfg.DBPassword,
cfg.DBHost,
cfg.DBPort,
cfg.DBName,
)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal("Failed to connect to database:", err)
}
return db
}
`;
// src/generators/languages/go/templates/database/mariadb/env.ts
var generateGoMariadbEnv = () => `DB_HOST=localhost
DB_PORT=3306
DB_USER=root
DB_PASSWORD=password
DB_NAME=mariadb
SERVER_PORT=8080
APP_ENV=development
TRUSTED_PROXIES=127.0.0.1
`;
// src/generators/languages/go/templates/database/postgresql/config.ts
var generateGoPostgresqlConfig = () => `package config
import (
"log"
"os"
"github.com/joho/godotenv"
)
type Config struct {
DBHost string
DBPort string
DBUser string
DBPassword string
DBName string
ServerPort string
Environment string
TrustedProxies string
}
func LoadConfig() *Config {
err := godotenv.Load()
if err != nil {
log.Println("Warning: .env file not found, using default values")
}
return &Config{
DBHost: getEnv("DB_HOST", "localhost"),
DBPort: getEnv("DB_PORT", "5432"),
DBUser: getEnv("DB_USER", "postgres"),
DBPassword: getEnv("DB_PASSWORD", "postgres"),
DBName: getEnv("DB_NAME", "postgres"),
ServerPort: getEnv("SERVER_PORT", "8080"),
Environment: getEnv("APP_ENV", "development"),
TrustedProxies: getEnv("TRUSTED_PROXIES", "127.0.0.1"),
}
}
func getEnv(key, fallback string) string {
if value, exists := os.LookupEnv(key); exists {
return value
}
return fallback
}
`;
// src/generators/languages/go/templates/database/postgresql/database.ts
var generateGoPostgresqlDatabase = () => `package database
import (
"fmt"
"log"
"project-name/pkg/config"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
func Connect() *gorm.DB {
// Load config
cfg := config.LoadConfig()
// Connect to PostgreSQL
dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=disable",
cfg.DBHost, cfg.DBUser, cfg.DBPassword, cfg.DBName, cfg.DBPort)
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal("Failed to connect to database:", err)
}
return db
}
`;
// src/generators/languages/go/templates/database/postgresql/env.ts
var generateGoPostgresqlEnv = () => `DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=postgres
DB_NAME=postgres
SERVER_PORT=8080
APP_ENV=development
TRUSTED_PROXIES=127.0.0.1
`;
// src/generators/languages/go/templates/database/sqlite/config.ts
var generateGoSqliteConfig = () => `package config
import (
"log"
"os"
"github.com/joho/godotenv"
)
type Config struct {
DBPath string // Path file SQLite
ServerPort string
Environment string
TrustedProxies string
}
func LoadConfig() *Config {
err := godotenv.Load()
if err != nil {
log.Println("Warning: .env file not found, using default values")
}
return &Config{
DBPath: getEnv("DB_PATH", "database.db"),
ServerPort: getEnv("SERVER_PORT", "8080"),
Environment: getEnv("APP_ENV", "development"),
TrustedProxies: getEnv("TRUSTED_PROXIES", "127.0.0.1"),
}
}
func getEnv(key, fallback string) string {
if value, exists := os.LookupEnv(key); exists {
return value
}
return fallback
}
`;
// src/generators/languages/go/templates/database/sqlite/database.ts
var generateGoSqliteDatabase = () => `package database
import (
"log"
"project-name/pkg/config"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
func Connect() *gorm.DB {
// Load config
cfg := config.LoadConfig()
// Connect to SQLite
db, err := gorm.Open(sqlite.Open(cfg.DBPath), &gorm.Config{})
if err != nil {
log.Fatal("Failed to connect to database:", err)
}
return db
}
`;
// src/generators/languages/go/templates/database/sqlite/env.ts
var generateGoSqliteEnv = () => `DB_PATH=database.db
SERVER_PORT=8080
APP_ENV=development
TRUSTED_PROXIES=127.0.0.1
`;
// src/generators/languages/go/templates/gorm/sql/entity.ts
var generateGoGormEntity = (name, fields) => {
const typeMapping = {
string: "string",
number: "float64",
boolean: "bool",
date: "time.Time",
text: "string",
json: "json.RawMessage",
enum: "string"
};
const fieldDefinitions = fields.map((field) => {
const goType = typeMapping[field.type] || "string";
const fieldName = field.name.charAt(0).toUpperCase() + field.name.slice(1);
let binding = "";
if (field.type === "string" || field.type === "text") {
binding = ' binding:"max=255"';
} else if (field.type === "number") {
binding = ' binding:"numeric"';
}
return ` ${fieldName} ${goType} \`json:"${field.name}"${binding}\``;
}).join(`
`);
return `package entity
import (
"time"
${fields.some((f) => f.type === "json") ? `
"encoding/json"` : ""}
"github.com/go-playground/validator/v10"
)
type ${name} struct {
ID uint \`json:"id" gorm:"primaryKey"\`
${fieldDefinitions}
CreatedAt time.Time \`json:"created_at"\`
UpdatedAt time.Time \`json:"updated_at"\`
}
func (p *${name}) Validate() error {
validate := validator.New()
return validate.Struct(p)
}
`;
};
// src/generators/languages/go/templates/gorm/sql/service.ts
var generateGoGormService = (name, pluralName) => `package service
import (
"project-name/internal/module/${name.toLowerCase()}/entity"
"gorm.io/gorm"
)
type ${name}Service struct {
db *gorm.DB
}
func New${name}Service(db *gorm.DB) *${name}Service {
return &${name}Service{db}
}
func (s *${name}Service) Create(${name.toLowerCase()} *entity.${name}) error {
if err := ${name.toLowerCase()}.Validate(); err != nil {
return err
}
return s.db.Create(${name.toLowerCase()}).Error
}
func (s *${name}Service) GetByID(id uint) (*entity.${name}, error) {
var ${name.toLowerCase()} entity.${name}
err := s.db.First(&${name.toLowerCase()}, id).Error
return &${name.toLowerCase()}, err
}
func (s *${name}Service) GetAll() ([]entity.${name}, error) {
var ${pluralName.toLowerCase()} []entity.${name}
err := s.db.Find(&${pluralName.toLowerCase()}).Error
return ${pluralName.toLowerCase()}, err
}
func (s *${name}Service) Update(${name.toLowerCase()} *entity.${name}) error {
if err := ${name.toLowerCase()}.Validate(); err != nil {
return err
}
// Cek apakah ${name.toLowerCase()} ada
var existing${name} entity.${name}
if err := s.db.First(&existing${name}, ${name.toLowerCase()}.ID).Error; err != nil {
return err
}
return s.db.Save(${name.toLowerCase()}).Error
}
func (s *${name}Service) Delete(id uint) error {
return s.db.Delete(&entity.${name}{}, id).Error
}
`;
// src/generators/languages/go/templates/gorm/sql/handler.ts
var generateGoGormHandler = (name, pluralName) => `package handler
import (
"net/http"
"project-name/internal/module/${name.toLowerCase()}/entity"
"project-name/internal/module/${name.toLowerCase()}/service"
"project-name/pkg/utils"
"strconv"
"github.com/gin-gonic/gin"
)
type ${name}Handler struct {
service *service.${name}Service
}
func New${name}Handler(service *service.${name}Service) *${name}Handler {
return &${name}Handler{service}
}
func (h *${name}Handler) Create(c *gin.Context) {
var ${name.toLowerCase()} entity.${name}
if err := c.ShouldBindJSON(&${name.toLowerCase()}); err != nil {
c.JSON(http.StatusBadRequest, utils.ErrorResponse(err.Error()))
return
}
if err := h.service.Create(&${name.toLowerCase()}); err != nil {
c.JSON(http.StatusInternalServerError, utils.ErrorResponse(err.Error()))
return
}
c.JSON(http.StatusCreated, utils.SuccessResponse(${name.toLowerCase()}))
}
func (h *${name}Handler) GetByID(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
if err != nil {
c.JSON(http.StatusBadRequest, utils.ErrorResponse("Invalid ID"))
return
}
${name.toLowerCase()}, err := h.service.GetByID(uint(id))
if err != nil {
c.JSON(http.StatusNotFound, utils.ErrorResponse("${name} not found"))
return
}
c.JSON(http.StatusOK, utils.SuccessResponse(${name.toLowerCase()}))
}
func (h *${name}Handler) GetAll(c *gin.Context) {
${pluralName.toLowerCase()}, err := h.service.GetAll()
if err != nil {
c.JSON(http.StatusInternalServerError, utils.ErrorResponse(err.Error()))
return
}
c.JSON(http.StatusOK, utils.SuccessResponse(${pluralName.toLowerCase()}))
}
func (h *${name}Handler) Update(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
if err != nil {
c.JSON(http.StatusBadRequest, utils.ErrorResponse("Invalid ID"))
return
}
var ${name.toLowerCase()} entity.${name}
if err := c.ShouldBindJSON(&${name.toLowerCase()}); err != nil {
c.JSON(http.StatusBadRequest, utils.ErrorResponse(err.Error()))
return
}
// Set ID dari parameter URL
${name.toLowerCase()}.ID = uint(id)
if err := h.service.Update(&${name.toLowerCase()}); err != nil {
c.JSON(http.StatusInternalServerError, utils.ErrorResponse(err.Error()))
return
}
c.JSON(http.StatusOK, utils.SuccessResponse(${name.toLowerCase()}))
}
func (h *${name}Handler) Delete(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
if err != nil {
c.JSON(http.StatusBadRequest, utils.ErrorResponse("Invalid ID"))
return
}
if err := h.service.Delete(uint(id)); err != nil {
c.JSON(http.StatusInternalServerError, utils.ErrorResponse(err.Error()))
return
}
c.JSON(http.StatusOK, utils.SuccessResponse("${name} deleted successfully"))
}
`;
// src/generators/languages/go/templates/gorm/sql/route.ts
var generateGoGormRoute = (name, pluralName) => `package handler
import (
"github.com/gin-gonic/gin"
)
func RegisterRoutes(router *gin.RouterGroup, handler *${name}Handler) {
${pluralName.toLowerCase()} := router.Group("/${pluralName.toLowerCase()}")
{
${pluralName.toLowerCase()}.POST("", handler.Create)
${pluralName.toLowerCase()}.GET("/:id", handler.GetByID)
${pluralName.toLowerCase()}.GET("", handler.GetAll)
${pluralName.toLowerCase()}.PUT("/:id", handler.Update)
${pluralName.toLowerCase()}.DELETE("/:id", handler.Delete)
}
}
`;
// src/generators/languages/go/templates/gorm/sql/main.ts
var generateGoGormMain = (name, existingModules = []) => {
const allModules = [...existingModules, { name, lowerName: name.toLowerCase() }];
const imports = allModules.map((module) => ` "project-name/internal/module/${module.lowerName}"`).join(`
`);
const initializations = allModules.map((module) => ` ${module.lowerName}.Initialize(db, api)`).join(`
`);
return `package main
import (
"log"
"strings"
${imports}
"project-name/pkg/config"
"project-name/pkg/database"
"project-name/pkg/middleware"
"github.com/gin-gonic/gin"
)
func main() {
// Load config
cfg := config.LoadConfig()
// Set mode berdasarkan environment
if cfg.Environment == "production" {
gin.SetMode(gin.ReleaseMode)
}
// Connect to database
db := database.Connect()
// Setup router
r := gin.Default()
// Set trusted proxies dari environment atau gunakan default
trustedProxies := strings.Split(cfg.TrustedProxies, ",")
r.SetTrustedProxies(trustedProxies)
r.Use(middleware.CORS())
// API routes
api := r.Group("/api")
// Initialize modules
${initializations}
// Start server
log.Printf("\uD83D\uDE80 Server running on port %s", cfg.ServerPort)
r.Run(":" + cfg.ServerPort)
}
`;
};
// src/generators/languages/go/templates/gorm/sql/middleware.ts
var generateGoGormMiddleware = () => `package middleware
import (
"github.com/gin-gonic/gin"
)
func Logger() gin.HandlerFunc {
return gin.Logger()
}
func CORS() gin.HandlerFunc {
return func(c *gin.Context) {
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
}
}
`;
// src/generators/languages/go/templates/gorm/sql/response.ts
var generateGoGormResponse = () => `package utils
type Response struct {
Success bool \`json:"success"\`
Data interface{} \`json:"data,omitempty"\`
Error string \`json:"error,omitempty"\`
}
func SuccessResponse(data interface{}) Response {
return Response{
Success: true,
Data: data,
}
}
func ErrorResponse(err string) Response {
return Response{
Success: false,
Error: err,
}
}
`;
// src/generators/utils/singular.ts
function singularize(word) {
const irregulars = {
Categories: "Category",
Properties: "Property",
Cities: "City",
Stories: "Story",
Babies: "Baby",
People: "Person",
Men: "Man",
Women: "Woman",
Children: "Child",
Teeth: "Tooth",
Feet: "Foot",
Mice: "Mouse",
Beliefs: "Belief"
};
if (irregulars[word.toLowerCase()]) {
return irregulars[word.toLowerCase()];
}
if (word.match(/ies$/)) {
return word.replace(/ies$/, "y");
}
if (word.match(/es$/)) {
return word.replace(/es$/, "");
}
if (word.match(/s$/)) {
return word.replace(/s$/, "");
}
return word;
}
// src/generators/languages/go/templates/gorm/sql/seedMain.ts
var generateGoGormSeedMain = (_name, pluralName, existingModules = []) => {
const allModules = [...existingModules, pluralName];
const entityImports = allModules.map((module) => ` ${module.toLowerCase()}Entity "project-name/internal/module/${singularize(module).toLowerCase()}/entity"`).join(`
`);
return `package main
import (
"fmt"
"log"
${entityImports}
"project-name/internal/seed"
"project-name/pkg/database"
"gorm.io/gorm"
)
// SeedFunction adalah tipe untuk fungsi seeding
type SeedFunction func(*gorm.DB) error
// runMigrations menjalankan migrasi sesuai urutan
func runMigrations(db *gorm.DB) error {
fmt.Println("\uD83D\uDE80 Running migrations in order...")
migrations := []interface{}{
${allModules.map((module) => `&${module.toLowerCase()}Entity.${module.slice(0, -1)}{}`).join(`,
`)},
// Tambahkan entity lain
}
for _, model := range migrations {
if err := db.AutoMigrate(model); err != nil {
return fmt.Errorf("error migrating %T: %w", model, err)
}
fmt.Printf("\uD83D\uDCDD Migrated %T successfully\\n", model)
}
return nil
}
// runSeeds menjalankan seeding sesuai urutan
func runSeeds(db *gorm.DB) error {
fmt.Println("\uD83C\uDF31 Running seeds in order...")
seeds := []struct {
name string
fn SeedFunction
}{
${allModules.map((module) => `{"${module.toLowerCase()}", seed.${module}}`).join(`,
`)},
// Tambahkan fungsi seed lainnya
}
for _, seed := range seeds {
fmt.Printf("\uD83C\uDF31 Seeding %s...", seed.name)
if err := seed.fn(db); err != nil {
return fmt.Errorf("error seeding %s: %w", seed.name, err)
}
fmt.Printf("\u2705 Seeded %s successfully\\n", seed.name)
}
return nil
}
func main() {
db := database.Connect()
if err := runMigrations(db); err != nil {
log.Fatalf("Error running migrations: %v", err)
}
if err := runSeeds(db); err != nil {
log.Fatalf("Error running seeds: %v", err)
}
log.Println("\u2705 All data migrated and seeded successfully")
}
`;
};
// src/generators/languages/go/templates/gorm/sql/seed.ts
var generateGoGormSeed = (name, pluralName) => `package seed
import (
"encoding/json"
"fmt"
${name.toLowerCase()}Entity "project-name/internal/module/${name.toLowerCase()}/entity"
"os"
"gorm.io/gorm"
)
// ${pluralName} - fungsi untuk seed data ${name.toLowerCase()}
func ${pluralName}(db *gorm.DB) error {
// Read JSON file
data, err := os.ReadFile("data/${pluralName.toLowerCase()}.json")
if err != nil {
return fmt.Errorf("error reading ${pluralName.toLowerCase()}.json: %w", err)
}
// Parse JSON data
var ${pluralName.toLowerCase()} []${name.toLowerCase()}Entity.${name}
err = json.Unmarshal(data, &${pluralName.toLowerCase()})
if err != nil {
return fmt.Errorf("error parsing ${pluralName.toLowerCase()}.json: %w", err)
}
// Seed data
for _, ${name.toLowerCase()} := range ${pluralName.toLowerCase()} {
if err := db.Create(&${name.toLowerCase()}).Error; err != nil {
return fmt.Errorf("error seeding ${name.toLowerCase()}: %w", err)
}
}
fmt.Println("\uD83C\uDF31 ${name} data seeded successfully!")
return nil
}
`;
// src/generators/languages/go/templates/gorm/sql/bootstrap.ts
var generateGoGormBootstrap = (name) => `package ${name.toLowerCase()}
import (
"project-name/internal/module/${name.toLowerCase()}/handler"
"project-name/internal/module/${name.toLowerCase()}/service"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// Initialize - Fungsi untuk menginisialisasi modul ${name.toLowerCase()}
func Initialize(db *gorm.DB, router *gin.RouterGroup) {
// Initialize service
${name.toLowerCase()}Service := service.New${name}Service(db)
// Initialize handler
${name.toLowerCase()}Handler := handler.New${name}Handler(${name.toLowerCase()}Service)
// Register routes
handler.RegisterRoutes(router, ${name.toLowerCase()}Handler)
}
`;
// src/generators/languages/go/src/mapping.ts
var configGenerators2 = {
postgresql: {
config: generateGoPostgresqlConfig,
database: generateGoPostgresqlDatabase,
env: generateGoPostgresqlEnv
},
mariadb: {
config: generateGoMariadbConfig,
database: generateGoMariadbDatabase,
env: generateGoMariadbEnv
},
sqlite: {
config: generateGoSqliteConfig,
database: generateGoSqliteDatabase,
env: generateGoSqliteEnv
}
};
var entityGenerator = generateGoGormEntity;
var serviceGenerator = generateGoGormService;
var handlerGenerator = generateGoGormHandler;
var routeGenerator = generateGoGormRoute;
var mainGenerator = generateGoGormMain;
var middlewareGenerator = generateGoGormMiddleware;
var responseGenerator = generateGoGormResponse;
var seedGenerators = {
main: generateGoGormSeedMain,
seed: generateGoGormSeed
};
var bootstrapGenerator = generateGoGormBootstrap;
// src/generators/languages/go/src/index.ts
async function generateGoCrud(name, fields, config) {
const { database, projectDir } = config;
const cwd = process.cwd();
const pluralName = pluralize(name);
let moduleName = "";
try {
const goModContent = await Bun.file(`${cwd}/go.mod`).text();
const moduleMatch = goModContent.match(/module\s+(.+)/);
if (moduleMatch && moduleMatch[1]) {
moduleName = moduleMatch[1].trim();
} else {
moduleName = path4.basename(cwd);
}
} catch (error) {
moduleName = path4.basename(cwd);
}
console.log(source_default.blue("\uD83D\uDCE6 Detail Generate:"));
console.log(source_default.yellow(`Database: ${database}`));
console.log(source_default.yellow(`Model: ${name}`));
console.log(source_default.yellow(`Project Directory: ${projectDir || "root"}`));
console.log(source_default.yellow(`Module Name: ${moduleName}`));
console.log(source_default.yellow("Fields:"));
fields.forEach((field) => {
console.log(source_default.yellow(` - ${field.name}: ${field.type}`));
});
const existingModules = await getExistingModules(projectDir);
const isFirstGenerate = existingModules.length === 0;
const pkgDir = `${cwd}/${projectDir ? projectDir + "/" : ""}pkg`;
const configDir = `${pkgDir}/config`;
const databaseDir = `${pkgDir}/database`;
const utilsDir = `${pkgDir}/utils`;
await Bun.spawn(["mkdir", "-p", configDir]).exited;
await Bun.spawn(["mkdir", "-p", databaseDir]).exited;
await Bun.spawn(["mkdir", "-p", utilsDir]).exited;
const dbConfig = configGenerators2[database];
if (!dbConfig) {
throw new Error(`Database ${database} belum didukung \uD83D\uDE22`);
}
await Bun.write(`${configDir}/config.go`, dbConfig.config().replace(/project-name/g, moduleName));
console.log(source_default.green("\u2705 Created config.go"));
await Bun.write(`${databaseDir}/database.go`, dbConfig.database().replace(/project-name/g, moduleName));
console.log(source_default.green("\u2705 Created database.go"));
if (dbConfig.env) {
await Bun.write(`${cwd}/${projectDir ? projectDir + "/" : ""}.env`, dbConfig.env());
console.log(source_default.green("\u2705 Created .env file"));
}
const internalDir = `${cwd}/${projectDir ? projectDir + "/" : ""}internal`;
const moduleDir = `${internalDir}/module/${name.toLowerCase()}`;
const entityDir = `${moduleDir}/entity`;
const handlerDir = `${moduleDir}/handler`;
const serviceDir = `${moduleDir}/service`;
await Bun.spawn(["mkdir", "-p", entityDir]).exited;
await Bun.spawn(["mkdir", "-p", handlerDir]).exited;
await Bun.spawn(["mkdir", "-p", serviceDir]).exited;
await Bun.write(`${entityDir}/${name.toLowerCase()}.go`, entityGenerator(name, fields).replace(/project-name/g, moduleName));
console.log(source_default.green(`\u2705 Created ${name.toLowerCase()}.go entity`));
await Bun.write(`${moduleDir}/bootstrap.go`, bootstrapGenerator(name).replace(/project-name/g, moduleName));
console.log(source_default.green(`\u2705 Created bootstrap.go`));
await Bun.write(`${serviceDir}/service.go`, serviceGenerator(name, pluralName).replace(/project-name/g, moduleName));
console.log(source_default.green(`\u2705 Created service.go`));
await Bun.write(`${handlerDir}/handler.go`, handlerGenerator(name, pluralName).replace(/project-name/g, moduleName));
console.log(source_default.green(`\u2705 Created handler.go`));
await Bun.write(`${handlerDir}/route.go`, routeGenerator(name, pluralName).replace(/project-name/g, moduleName));
console.log(source_default.green(`\u2705 Created route.go`));
await Bun.write(`${pkgDir}/middleware/middleware.go`, middlewareGenerator());
console.log(source_default.green(`\u2705 Created middleware.go`));
await Bun.write(`${utilsDir}/response.go`, responseGenerator());
console.log(source_default.green(`\u2705 Created response.go`));
const cmdDir = `${cwd}/${projectDir ? projectDir + "/" : ""}cmd`;
await Bun.spawn(["mkdir", "-p", `${cmdDir}/main`]).exited;
await Bun.write(`${cmdDir}/main/main.go`, mainGenerator(name, existingModules).replace(/project-name/g, moduleName));
console.log(source_default.green(`\u2705 Created main.go`));
const seedDir = `${cwd}/${projectDir ? projectDir + "/" : ""}cmd/seed`;
await Bun.spawn(["mkdir", "-p", seedDir]).exited;
if (isFirstGenerate) {
await Bun.write(`${seedDir}/main.go`, seedGenerators.main(name, pluralName).replace(/project-name/g, moduleName));
} else {
const existingModuleNames = existingModules.map((m) => pluralize(m.name));
await Bun.write(`${seedDir}/main.go`, seedGenerators.main(name, pluralName, existingModuleNames).replace(/project-name/g, moduleName));
}
console.log(source_default.green(`\u2705 Created seed main.go`));
await Bun.spawn(["mkdir", "-p", `${internalDir}/seed`]).exited;
await Bun.write(`${internalDir}/seed/${name.toLowerCase()}.go`, seedGenerators.seed(name, pluralName).replace(/project-name/g, moduleName));
console.log(source_default.green(`\u2705 Created seed ${name.toLowerCase()}.go`));
const dataDir = `${cwd}/${projectDir ? projectDir + "/" : ""}data`;
await Bun.spawn(["mkdir", "-p", dataDir]).exited;
await Bun.write(`${dataDir}/${pluralName.toLowerCase()}.json`, generateJSONData(name, fields));
console.log(source_default.green(`\u2705 Created ${pluralName.toLowerCase()}.json with sample data`));
await updateMainGo(name, projectDir, isFirstGenerate);
await updateSeedMain(name, projectDir, isFirstGenerate);
console.log(source_default.green(`
\u2728 Files generated successfully!`));
}
// src/generators/languages/go/index.ts
async function generateCommand2(name, fields) {
try {
console.log(source_default.cyan(`
\uD83D\uDE80 Memulai generate CRUD untuk Go...
`));
const config = await readConfig();
const parsedFields = parseFields(fields);
await generateGoCrud(name, parsedFields, config);
console.log(source_default.green(`
\u2728 Generate CRUD Go berhasil!
`));
} catch (error) {
const errMsg = error instanceof Error ? source_default.red(error.message) : "Unknown error occurred";
console.error(source_default.red(`
\u274C Aduh error nih: ${errMsg}
`));
process.exit(1);
}
}
// src/index.ts
var promptsConfig5 = {
onCancel: () => {
console.log(source_default.yellow(`
\uD83D\uDED1 Operasi dibatalkan oleh pengguna`));
process.exit(0);
}
};
var packageJson;
var version = process.env.HENOTIC_VERSION;
if (version) {
packageJson = {
name: "henotic-cli",
version,
author: "Hens MSN <hendymms@engineer.com>",
description: "Henotic CLI is the ultimate multi-language backend generator"
};
} else {
try {
packageJson = JSON.parse(await Bun.file(`${import.meta.dir}/../package.json`).text());
} catch (error) {
console.error(source_default.yellow("\u26A0\uFE0F Tidak dapat membaca versi, menggunakan versi default"));
packageJson = {
name: "henotic-cli",
version: "unknown",
author: "Hens MSN <hendymms@engineer.com>",
description: "Henotic CLI is the ultimate multi-language backend generator"
};
}
}
function showHelp() {
console.log(source_default.bold(`
\uD83E\uDD9C Henotic CLI - The Ultimate Backend Generator
`));
console.log(`
${source_default.bold("Usage:")}
${source_default.cyan("henotic new <project-name>")} Buat project baru
${source_default.cyan("henotic generate <model>")} Generate model baru
${source_default.cyan("henotic seed <module>")} Jalankan seed pada module
${source_default.cyan("henotic unseed <module>")} Jalankan unseed pada module
${source_default.cyan("henotic migrate <module>")} Jalankan migrate pada module
${source_default.cyan("henotic drop <module>")} Jalankan drop table pada module
${source_default.cyan("henotic reset <module>")} Drop + migrate + seed pada module
${source_default.cyan("henotic start")} Jalankan aplikasi (production)
${source_default.cyan("henotic dev")} Jalankan aplikasi (development)
${source_default.cyan("henotic build")} Build aplikasi (TypeScript)
${source_default.cyan("henotic [options]")}
${source_default.bold("Options:")}
${source_default.green("-h, --help")} Tampilkan bantuan
${source_default.green("-v, --version")} Tampilkan versi CLI
${source_default.green("--all")} Jalankan pada semua module (untuk seed/unseed/migrate/drop/reset)
${source_default.bold("Examples:")}
${source_default.cyan("henotic new my-app")} Buat project di folder baru
${source_default.cyan("henotic new .")} Inisialisasi di folder saat ini
${source_default.cyan("henotic generate Product title:string price:number")} Generate model
${source_default.cyan("henotic seed User")} Jalankan seed pada module User
${source_default.cyan("henotic reset User")} Reset module User (drop + migrate + seed)
${source_default.cyan("henotic reset --all")} Reset semua module
${source_default.cyan("henotic dev")} Jalankan aplikasi dalam mode development
${source_default.cyan("henotic -v")} Cek versi terinstall
${source_default.cyan("henotic update")} Update CLI ke versi terbaru
`);
}
function showVersion() {
console.log(`
\uD83E\uDD9C Henotic v${packageJson.version}`);
console.log(`\uD83C\uDF10 ${source_default.blue("https://github.com/hens-msn")}
`);
}
async function deleteHenotic() {
const { confirm } = await import_prompts7.default({
type: "confirm",
name: "confirm",
message: "Apakah kamu yakin ingin menghapus Henotic CLI?",
initial: false
}, promptsConfig5);
if (!confirm) {
console.log(source_default.yellow("\u274C Penghapusan Henotic CLI dibatalkan"));
return;
}
console.log(source_default.cyan(`
\uD83D\uDDD1\uFE0F Menghapus Henotic CLI...`));
try {
const osProcess = Bun.spawn(["uname", "-s"], {
stdout: "pipe"
});
const osOutput = await new Response(osProcess.stdout).text();
const os2 = osOutput.trim();
const homeDir = process.env.HOME || process.env.USERPROFILE || ".";
const installDir = `${homeDir}/.henotic`;
const binLocations = [
"/usr/local/bin/henotic",
`${homeDir}/.local/bin/henotic`,
"/usr/bin/henotic"
];
if (os2 === "Linux" || os2 === "Darwin") {
console.log(source_default.cyan("\uD83D\uDD0D Mencari dan menghapus symlink Henotic..."));
for (const binPath of binLocations) {
const fileExists3 = await Bun.file(binPath).exists();
if (fileExists3) {
console.log(source_default.cyan(`\uD83D\uDDD1\uFE0F Menghapus ${binPath}...`));
let rmProcess = Bun.spawn(["rm", "-f", binPath], {
stdio: ["inherit", "inherit", "inherit"]
});
let exitCode = await rmProcess.exited;
if (exitCode !== 0) {
console.log(source_default.yellow(`\u26A0\uFE0F Memerlukan hak akses root untuk menghapus ${binPath}...`));
rmProcess = Bun.spawn(["sudo", "rm", "-f", binPath], {
stdio: ["inherit", "inherit", "inherit"]
});
await rmProcess.exited;
}
}
}
}
if (await Bun.file(installDir).exists()) {
console.log(source_default.cyan(`\uD83D\uDDD1\uFE0F Menghapus direktori instalasi ${installDir}...`));
const rmDirProcess = Bun.spawn(["rm", "-rf", installDir], {
stdio: ["inherit", "inherit", "inherit"]
});
await rmDirProcess.exited;
}
console.log(source_default.cyan("\uD83D\uDD0D Memeriksa apakah diinstall dengan bun..."));
const bunListProcess = Bun.spawn(["bun", "pm", "ls", "-g"], {
stdout: "pipe"
});
const bunListOutput = await new Response(bunListProcess.stdout).text();
if (bunListOutput.includes("henotic-cli")) {
console.log(source_default.cyan("\uD83D\uDDD1\uFE0F Menghapus henotic-cli dari bun global packages..."));
const deleteProcess = Bun.spawn([
"bun",
"rm",
"-g",
"--silent",
"henotic-cli"
], {
stdio: ["inherit", "inherit", "inherit"]
});
await deleteProcess.exited;
}
const whichProcess = Bun.spawn(["which", "henotic"], {
stdout: "pipe",
stderr: "pipe"
});
await whichProcess.exited;
if (whichProcess.exitCode === 0) {
const henoticPath = await new Response(whichProcess.stdout).text();
console.log(source_default.yellow(`\u26A0\uFE0F Henotic masih terdeteksi di ${henoticPath.trim()}`));
console.log(source_default.yellow(" Mungkin ada instalasi lain yang belum terhapus."));
} else {
console.log(source_default.green("\u2705 Henotic CLI berhasil dihapus dari sistem!"));
}
console.log(source_default.cyan("\uD83D\uDC4B Terima kasih telah menggunakan Henotic CLI!"));
} catch (error) {
console.error(source_default.red(`\u274C Gagal menghapus Henotic CLI: ${error instanceof Error ? error.message : String(error)}`));
process.exit(1);
}
}
async function getLatestVersion() {
try {
console.log(source_default.cyan("\uD83D\uDD0D Mengecek versi terbaru..."));
const response = await fetch("https://api.github.com/repos/hens-msn/henotic/releases/latest", {
headers: {
Accept: "application/vnd.github.v3+json",
"User-Agent": "Henotic-CLI"
}
});
if (response.ok) {
const data = await response.json();
if (data.assets && data.assets.length > 0) {
for (const asset of data.assets) {
const versionMatch = asset.name.match(/v(\d+\.\d+\.\d+)/);
if (versionMatch && versionMatch[1]) {
return versionMatch[1];
}
}
}
}
return null;
} catch (error) {
console.error(source_default.yellow(`\u26A0\uFE0F Gagal mengecek versi terbaru: ${error instanceof Error ? error.message : String(error)}`));
return null;
}
}
async function updateHenotic() {
console.log(source_default.cyan(`
\uD83D\uDE80 Updating Henotic CLI...`));
const latestVersion = await getLatestVersion();
const currentVersion = packageJson.version;
if (latestVersion) {
if (latestVersion === currentVersion) {
console.log(source_default.green(`\u2705 Henotic CLI sudah versi terbaru (v${currentVersion})!`));
return;
} else {
console.log(source_default.cyan(`\uD83D\uDCCC Versi terbaru: v${latestVersion} (terpasang: v${currentVersion})`));
}
} else {
console.log(source_default.yellow(`\u26A0\uFE0F Tidak dapat mengecek versi terbaru. Melanjutkan dengan versi saat ini (v${currentVersion}).`));
}
const version2 = latestVersion || currentVersion;
const tempDir = `/tmp/henotic-update-${Date.now()}`;
try {
await Bun.spawn(["mkdir", "-p", tempDir], {
stdio: ["inherit", "inherit", "inherit"]
}).exited;
const osProcess = Bun.spawn(["uname", "-s"], {
stdout: "pipe"
});
const osOutput = await new Response(osProcess.stdout).text();
const os2 = osOutput.trim();
const archProcess = Bun.spawn(["uname", "-m"], {
stdout: "pipe"
});
const archOutput = await new Response(archProcess.stdout).text();
const arch = archOutput.trim();
console.log(source_default.cyan(`\uD83D\uDD0D Terdeteksi sistem: ${os2} ${arch}`));
let downloadUrl = "";
let filename = "";
if (os2 === "Linux") {
if (arch === "x86_64") {
downloadUrl = `https://github.com/hens-msn/henotic/releases/download/henotic/henotic-linux-x64-v${version2}.tar.gz`;
filename = `henotic-linux-x64-v${version2}.tar.gz`;
} else {
throw new Error(`Arsitektur Linux ${arch} belum didukung.`);
}
} else if (os2 === "Darwin") {
if (arch === "arm64") {
downloadUrl = `https://github.com/hens-msn/henotic/releases/download/henotic/henotic-mac-arm64-v${version2}.tar.gz`;
filename = `henotic-mac-arm64-v${version2}.tar.gz`;
} else {
throw new Error(`Arsitektur macOS ${arch} belum didukung.`);
}
} else if (os2.includes("MINGW") || os2.includes("MSYS") || os2.includes("CYGWIN")) {
downloadUrl = `https://github.com/hens-msn/henotic/releases/download/henotic/henotic-win-v${version2}.exe`;
filename = `henotic-win-v${version2}.exe`;
} else {
throw new Error(`OS ${os2} tidak didukung.`);
}
console.log(source_default.cyan(`\uD83D\uDCE5 Mengunduh Henotic dari ${downloadUrl}...`));
const downloadProcess = Bun.spawn(["curl", "-L", downloadUrl, "-o", `${tempDir}/${filename}`], {
stdio: ["inherit", "inherit", "inherit"]
});
await downloadProcess.exited;
if (downloadProcess.exitCode !== 0) {
throw new Error("Gagal mengunduh file update.");
}
const statProcess = Bun.spawn(["stat", "-c", "%s", `${tempDir}/${filename}`], {
stdout: "pipe"
});
const fileSize = parseInt(await new Response(statProcess.stdout).text().then((s) => s.trim()), 10);
if (isNaN(fileSize) || fileSize < 1000) {
throw new Error(`File yang diunduh terlalu kecil (${fileSize} bytes). URL mungkin tidak valid.`);
}
let executablePath = "";
if (filename.endsWith(".tar.gz")) {
console.log(source_default.cyan("\uD83D\uDCE6 Mengekstrak file tar.gz..."));
const extractProcess = Bun.spawn(["tar", "-xzf", `${tempDir}/${filename}`, "-C", tempDir], {
stdio: ["inherit", "inherit", "inherit"]
});
await extractProcess.exited;
if (extractProcess.exitCode !== 0) {
throw new Error("Gagal mengekstrak file tar.gz.");
}
const findProcess = Bun.spawn(["find", tempDir, "-type", "f", "-executable"], {
stdout: "pipe"
});
const findOutput = await new Response(findProcess.stdout).text();
const executableFiles = findOutput.trim().split(`
`).filter(Boolean);
if (executableFiles.length === 0) {
console.log(source_default.yellow("\u26A0\uFE0F Tidak dapat menemukan file executable dalam tar.gz."));
const lsProcess = Bun.spawn(["ls", "-la", tempDir], {
stdio: ["inherit", "inherit", "inherit"]
});
await lsProcess.exited;
throw new Error("Tidak dapat menemukan file executable dalam tar.gz.");
}
executablePath = executableFiles[0];
console.log(source_default.cyan(`\u2705 File executable ditemukan: ${executablePath}`));
} else {
executablePath = `${tempDir}/${filename}`;
await Bun.spawn(["chmod", "+x", executablePath], {
stdio: ["inherit", "inherit", "inherit"]
}).exited;
}
const installDir = os2 === "Linux" || os2 === "Darwin" ? "/usr/local/bin" : ".";
if (os2 === "Linux" || os2 === "Darwin") {
console.log(source_default.cyan(`\uD83D\uDCCB Menginstall ke ${installDir}/henotic...`));
const tempExecutable = `${installDir}/henotic.new`;
let installProcess = Bun.spawn(["cp", executablePath, tempExecutable], {
stdio: ["inherit", "inherit", "inherit"]
});
let exitCode = await installProcess.exited;
if (exitCode !== 0) {
console.log(source_default.yellow("\u26A0\uFE0F Memerlukan hak akses root, mencoba dengan sudo..."));
installProcess = Bun.spawn(["sudo", "cp", executablePath, tempExecutable], {
stdio: ["inherit", "inherit", "inherit"]
});
exitCode = await installProcess.exited;
if (exitCode !== 0) {
throw new Error(`Gagal menyalin ke ${tempExecutable}`);
}
await Bun.spawn(["sudo", "chmod", "+x", tempExecutable], {
stdio: ["inherit", "inherit", "inherit"]
}).exited;
console.log(source_default.cyan("\uD83D\uDD04 Mengganti file executable lama..."));
const mvProcess = Bun.spawn(["sudo", "mv", "-f", tempExecutable, `${installDir}/henotic`], {
stdio: ["inherit", "inherit", "inherit"]
});
exitCode = await mvProcess.exited;
if (exitCode !== 0) {
console.log(source_default.yellow("\u26A0\uFE0F Tidak dapat mengganti file yang sedang digunakan."));
console.log(source_default.yellow(" File update tersedia di " + tempExecutable));
console.log(source_default.yellow(" Silakan tutup terminal ini dan jalankan:"));
console.log(source_default.cyan(` sudo mv -f ${tempExecutable} ${installDir}/henotic`));
}
} else {
await Bun.spawn(["chmod", "+x", tempExecutable], {
stdio: ["inherit", "inherit", "inherit"]
}).exited;
console.log(source_default.cyan("\uD83D\uDD04 Mengganti file executable lama..."));
const mvProcess = Bun.spawn(["mv", "-f", tempExecutable, `${installDir}/henotic`], {
stdio: ["inherit", "inherit", "inherit"]
});
exitCode = await mvProcess.exited;
if (exitCode !== 0) {
console.log(source_default.yellow("\u26A0\uFE0F Memerlukan hak akses root, mencoba dengan sudo..."));
const sudoMvProcess = Bun.spawn(["sudo", "mv", "-f", tempExecutable, `${installDir}/henotic`], {
stdio: ["inherit", "inherit", "inherit"]
});
exitCode = await sudoMvProcess.exited;
if (exitCode !== 0) {
console.log(source_default.yellow("\u26A0\uFE0F Tidak dapat mengganti file yang sedang digunakan."));
console.log(source_default.yellow(" File update tersedia di " + tempExecutable));
console.log(source_default.yellow(" Silakan tutup terminal ini dan jalankan:"));
console.log(source_default.cyan(` sudo mv -f ${tempExecutable} ${installDir}/henotic`));
}
}
}
} else {
console.log(source_default.yellow("\u26A0\uFE0F Untuk Windows, silakan install manual dengan menjalankan file yang diunduh."));
console.log(source_default.cyan(`\uD83D\uDCCB File executable tersedia di: ${executablePath}`));
}
await Bun.spawn(["rm", "-rf", tempDir], {
stdio: ["inherit", "inherit", "inherit"]
}).exited;
console.log(source_default.green("\u2705 Henotic CLI berhasil diupdate!"));
console.log(source_default.cyan("\uD83D\uDD04 Silakan restart terminal untuk menggunakan versi baru."));
} catch (error) {
console.error(source_default.red(`\u274C Gagal mengupdate Henotic CLI: ${error instanceof Error ? error.message : String(error)}`));
await Bun.spawn(["rm", "-rf", tempDir], {
stdio: ["inherit", "inherit", "inherit"]
}).exited;
process.exit(1);
}
}
async function generateModel(modelName, fields) {
if (!modelName || fields.length === 0) {
console.error(source_default.red(`
\u274C Format command generate: henotic generate <ModelName> <field:type> ...`));
console.log(source_default.yellow("Contoh: henotic generate Product title:string price:number"));
process.exit(1);
}
try {
const config = JSON.parse(await Bun.file("henotic.config.json").text());
if (config.language === "typescript") {
await generateCommand(modelName, fields);
} else if (config.language === "golang" || config.language === "go") {
await generateCommand2(modelName, fields);
} else {
console.error(source_default.red(`
\u274C Generator untuk ${config.language} belum tersedia!`));
process.exit(1);
}
} catch (error) {
console.error(source_default.red(`
\u274C Gagal generate - pastikan sudah di dalam project henotic!`));
console.log(source_default.yellow("Tips: Jalankan dari root project yg sudah di-init"));
process.exit(1);
}
}
async function seedModule(moduleName, options) {
try {
const config = await readConfig();
const modulePath = config.projectDir ? `${config.projectDir}/modules` : "modules";
if (config.language === "typescript") {
const seedProcess = Bun.spawn([
"bun",
`${modulePath}/${pluralize(moduleName).toLowerCase()}/${moduleName.toLowerCase()}.seed.ts`,
"seed"
], {
stdio: ["inherit", "inherit", "inherit"]
});
await seedProcess.exited;
} else if (config.language === "golang" || config.language === "go") {
const seedProcess = Bun.spawn([
"go",
"run",
"cmd/seed/main.go"
], {
stdio: ["inherit", "inherit", "inherit"]
});
await seedProcess.exited;
}
} catch (error) {
console.error(source_default.red(`
\u274C Gagal seed - pastikan sudah di dalam project henotic!`));
process.exit(1);
}
}
async function unseedModule(moduleName, options) {
try {
const config = await readConfig();
const modulePath = config.projectDir ? `${config.projectDir}/modules` : "modules";
if (config.language === "typescript") {
const unseedProcess = Bun.spawn([
"bun",
`${modulePath}/${pluralize(moduleName).toLowerCase()}/${moduleName.toLowerCase()}.seed.ts`,
"unseed"
], {
stdio: ["inherit", "inherit", "inherit"]
});
await unseedProcess.exited;
} else if (config.language === "golang" || config.language === "go") {
console.log(source_default.yellow(`
\u26A0\uFE0F Untuk golang, gunakan henotic seed saja karena sudah termasuk unseed.`));
process.exit(0);
}
} catch (error) {
console.error(source_default.red(`
\u274C Gagal unseed - pastikan sudah di dalam project henotic!`));
process.exit(1);
}
}
async function migrateModule(moduleName, options) {
try {
const config = await readConfig();
const modulePath = config.projectDir ? `${config.projectDir}/modules` : "modules";
if (config.language === "typescript") {
const migrateProcess = Bun.spawn([
"bun",
`${modulePath}/${pluralize(moduleName).toLowerCase()}/${moduleName.toLowerCase()}.migrate.ts`,
"up"
], {
stdio: ["inherit", "inherit", "inherit"]
});
await migrateProcess.exited;
} else if (config.language === "golang" || config.language === "go") {
console.log(source_default.yellow(`
\u26A0\uFE0F Untuk golang, gunakan henotic seed saja karena sudah termasuk migrate.`));
process.exit(0);
}
} catch (error) {
console.error(source_default.red(`
\u274C Gagal migrate - pastikan sudah di dalam project henotic!`));
process.exit(1);
}
}
async function dropModule(moduleName, options) {
try {
const config = await readConfig();
const modulePath = config.projectDir ? `${config.projectDir}/modules` : "modules";
if (config.language === "typescript") {
const dropProcess = Bun.spawn([
"bun",
`${modulePath}/${pluralize(moduleName).toLowerCase()}/${moduleName.toLowerCase()}.migrate.ts`,
"down"
], {
stdio: ["inherit", "inherit", "inherit"]
});
await dropProcess.exited;
} else if (config.language === "golang" || config.language === "go") {
console.log(source_default.yellow(`
\u26A0\uFE0F Untuk golang, gunakan henotic seed saja karena sudah termasuk drop.`));
process.exit(0);
}
} catch (error) {
console.error(source_default.red(`
\u274C Gagal drop - pastikan sudah di dalam project henotic!`));
process.exit(1);
}
}
async function runDev() {
try {
const config = await readConfig();
console.log(source_default.cyan(`
\uD83D\uDE80 Menjalankan aplikasi dalam mode development...`));
if (config.language === "typescript") {
if (config.framework === "next") {
const devProcess = Bun.spawn(["bun", "next", "dev"], {
stdio: ["inherit", "inherit", "inherit"]
});
await devProcess.exited;
} else {
const entryPoint = config.projectDir ? `${config.projectDir}/index.ts` : "index.ts";
const devProcess = Bun.spawn(["bun", entryPoint], {
stdio: ["inherit", "inherit", "inherit"]
});
await devProcess.exited;
}
} else if (config.language === "golang" || config.language === "go") {
const devProcess = Bun.spawn(["go", "run", "cmd/main/main.go"], {
stdio: ["inherit", "inherit", "inherit"],
env: { ...process.env, APP_ENV: "development" }
});
await devProcess.exited;
} else {
console.error(source_default.red(`
\u274C Bahasa ${config.language} belum didukung untuk mode development!`));
process.exit(1);
}
} catch (error) {
console.error(source_default.red(`
\u274C Gagal menjalankan aplikasi - pastikan sudah di dalam project henotic!`));
process.exit(1);
}
}
async function runStart() {
try {
const config = await readConfig();
console.log(source_default.cyan(`
\uD83D\uDD28 Building aplikasi terlebih dahulu...`));
await buildApp();
console.log(source_default.cyan(`
\uD83D\uDE80 Menjalankan aplikasi dalam mode production...`));
if (config.language === "typescript") {
if (config.framework === "next") {
const startProcess = Bun.spawn(["bun", "next", "start"], {
stdio: ["inherit", "inherit", "inherit"],
cwd: process.cwd()
});
await startProcess.exited;
} else {
const startProcess = Bun.spawn(["bun", "dist/index.js"], {
stdio: ["inherit", "inherit", "inherit"],
cwd: process.cwd(),
env: { ...process.env, NODE_ENV: "production" }
});
await startProcess.exited;
}
} else if (config.language === "golang" || config.language === "go") {
const startProcess = Bun.spawn(["./dist/app"], {
stdio: ["inherit", "inherit", "inherit"],
cwd: process.cwd(),
env: { ...process.env, APP_ENV: "production" }
});
await startProcess.exited;
} else {
console.error(source_default.red(`
\u274C Bahasa ${config.language} belum didukung untuk mode production!`));
process.exit(1);
}
} catch (error) {
console.error(source_default.red(`
\u274C Gagal menjalankan aplikasi - pastikan sudah di dalam project henotic!`));
console.log(source_default.yellow(`Detail error: ${error instanceof Error ? error.message : String(error)}`));
process.exit(1);
}
}
async function buildApp() {
try {
const config = await readConfig();
if (config.language === "typescript") {
console.log(source_default.cyan(`
\uD83D\uDD28 Building aplikasi TypeScript...`));
if (config.framework === "next") {
const buildProcess = Bun.spawn(["bun", "next", "build"], {
stdio: ["inherit", "inherit", "inherit"],
cwd: process.cwd()
});
await buildProcess.exited;
if (buildProcess.exitCode === 0) {
console.log(source_default.green(`
\u2705 Build Next.js berhasil!`));
} else {
console.error(source_default.red(`
\u274C Build Next.js gagal!`));
process.exit(1);
}
} else {
const entryPoint = config.projectDir ? `${config.projectDir}/index.ts` : "index.ts";
let finalEntryPoint = entryPoint;
if (!await Bun.file(entryPoint).exists()) {
console.log(source_default.yellow(`
\u26A0\uFE0F File ${entryPoint} tidak ditemukan, mencoba mencari index.ts di root...`));
if (await Bun.file("index.ts").exists()) {
finalEntryPoint = "index.ts";
} else {
throw new Error(`File entrypoint tidak ditemukan: ${entryPoint} atau index.ts`);
}
}
console.log(source_default.cyan("\uD83E\uDDF9 Membersihkan folder dist..."));
const rmProcess = Bun.spawn(["rm", "-rf", "dist"], {
stdio: ["inherit", "inherit", "inherit"],
cwd: process.cwd()
});
await rmProcess.exited;
console.log(source_default.cyan("\uD83D\uDD28 Building dengan Bun..."));
const buildProcess = Bun.spawn(["bun", "build", finalEntryPoint, "--outdir", "./dist", "--target", "bun"], {
stdio: ["inherit", "inherit", "inherit"],
cwd: process.cwd()
});
await buildProcess.exited;
if (buildProcess.exitCode === 0) {
console.log(source_default.green(`
\u2705 Build berhasil! Output tersedia di folder ./dist`));
} else {
console.error(source_default.red(`
\u274C Build gagal!`));
process.exit(1);
}
}
} else if (config.language === "golang" || config.language === "go") {
console.log(source_default.cyan(`
\uD83D\uDD28 Building aplikasi Go...`));
const mkdirProcess = Bun.spawn(["mkdir", "-p", "./dist"], {
stdio: ["inherit", "inherit", "inherit"],
cwd: process.cwd()
});
await mkdirProcess.exited;
const buildProcess = Bun.spawn(["go", "build", "-o", "./dist/app", "./cmd/main/main.go"], {
stdio: ["inherit", "inherit", "inherit"],
cwd: process.cwd()
});
await buildProcess.exited;
if (buildProcess.exitCode === 0) {
console.log(source_default.green(`
\u2705 Build berhasil! Output tersedia di ./dist/app`));
} else {
console.error(source_default.red(`
\u274C Build gagal!`));
process.exit(1);
}
} else {
console.error(source_default.red(`
\u274C Bahasa ${config.language} belum didukung untuk build!`));
process.exit(1);
}
} catch (error) {
console.error(source_default.red(`
\u274C Gagal build aplikasi - pastikan sudah di dalam project henotic!`));
console.log(source_default.yellow(`Detail error: ${error instanceof Error ? error.message : String(error)}`));
process.exit(1);
}
}
async function resetModule(moduleName, options) {
try {
const config = await readConfig();
if (config.language === "typescript") {
console.log(source_default.cyan(`
\uD83D\uDD04 Melakukan reset pada module ${options.all ? "semua" : moduleName}...`));
console.log(source_default.yellow(`
\uD83D\uDCE5 Menjalankan drop...`));
await dropModule(moduleName, options);
console.log(source_default.yellow(`
\uD83D\uDCE4 Menjalankan migrate...`));
await migrateModule(moduleName, options);
console.log(source_default.yellow(`
\uD83C\uDF31 Menjalankan seed...`));
await seedModule(moduleName, options);
console.log(source_default.green(`
\u2705 Reset ${options.all ? "semua module" : `module ${moduleName}`} berhasil!`));
} else if (config.language === "golang" || config.language === "go") {
console.log(source_default.cyan(`
\uD83D\uDD04 Untuk Go, cukup jalankan seed yang sudah mencakup reset...`));
await seedModule(moduleName, options);
} else {
console.error(source_default.red(`
\u274C Bahasa ${config.language} belum didukung untuk reset!`));
process.exit(1);
}
} catch (error) {
console.error(source_default.red(`
\u274C Gagal reset - pastikan sudah di dalam project henotic!`));
console.log(source_default.yellow(`Detail error: ${error instanceof Error ? error.message : String(error)}`));
process.exit(1);
}
}
var args = Bun.argv;
var command = args[2];
var projectName = args[3];
var hasAllFlag = args.includes("--all");
switch (command) {
case "new":
if (!projectName) {
console.error(source_default.red(`
\u274C Nama project harus diisi!`));
showHelp();
process.exit(1);
}
await init(projectName);
break;
case "generate":
await generateModel(args[3], args.slice(4));
break;
case "seed":
await seedModule(hasAllFlag ? "" : args[3], { all: hasAllFlag });
break;
case "unseed":
await unseedModule(hasAllFlag ? "" : args[3], { all: hasAllFlag });
break;
case "migrate":
await migrateModule(hasAllFlag ? "" : args[3], { all: hasAllFlag });
break;
case "drop":
await dropModule(hasAllFlag ? "" : args[3], { all: hasAllFlag });
break;
case "reset":
await resetModule(hasAllFlag ? "" : args[3], { all: hasAllFlag });
break;
case "dev":
await runDev();
break;
case "start":
await runStart();
break;
case "build":
await buildApp();
break;
case "--version":
case "-v":
showVersion();
break;
case "--help":
case "-h":
case undefined:
showHelp();
break;
case "update":
await updateHenotic();
break;
case "delete":
await deleteHenotic();
break;
default:
console.error(source_default.red(`
\u274C Command tidak valid: ${command}`));
showHelp();
process.exit(1);
}