4bnode
Version:
4bnode is a CLI-powered backend development platform with a built-in visual dashboard to generate, manage, and test Node.js/Express APIs faster.
133 lines (116 loc) • 3.71 kB
JavaScript
import fs from "fs";
import path from "path";
import { getProjectRoot } from "./project.js";
import { ERROR_HANDLER_MARKER, insertBeforeListenContent } from "./codegen.js";
function getIndexPath() {
return path.join(getProjectRoot(), "index.js");
}
function readIndex() {
return fs.readFileSync(getIndexPath(), "utf8");
}
function writeIndex(content) {
fs.writeFileSync(getIndexPath(), content, "utf8");
}
export function addImport(importStatement) {
let content = readIndex();
if (!content.includes(importStatement.trim())) {
content = importStatement.trim() + "\n" + content;
writeIndex(content);
}
}
export function addRouteRegistration(importLine, useLine) {
let content = readIndex();
if (!content.includes(importLine.trim())) {
content = importLine.trim() + "\n" + content;
}
if (!content.includes(useLine.trim())) {
// The central error handler (added by `add security`) must stay last. If it's
// present, register new routes ABOVE it so notFound doesn't swallow them.
if (content.includes(ERROR_HANDLER_MARKER)) {
content = content.replace(
ERROR_HANDLER_MARKER,
useLine.trim() + "\n\n" + ERROR_HANDLER_MARKER
);
} else if (content.includes("app.listen(port")) {
content = content.replace(
"app.listen(port",
useLine.trim() + "\n" + "app.listen(port"
);
} else if (content.includes("server.listen(port")) {
content = content.replace(
"server.listen(port",
useLine.trim() + "\n" + "server.listen(port"
);
} else if (content.match(/^startServer\(/m)) {
content = content.replace(
/^startServer\(/m,
useLine.trim() + "\n" + "startServer("
);
}
}
writeIndex(content);
}
export function insertBeforeListen(codeBlock) {
writeIndex(insertBeforeListenContent(readIndex(), codeBlock));
}
export function replaceAppListen(newListenBlock) {
let content = readIndex();
// If using startServer() pattern, just swap app.listen → server.listen inside it
if (content.includes("startServer(")) {
content = content.replace(
/const listener = app\.listen\(tryPort\)/,
"const listener = server.listen(tryPort)"
);
// Also swap standalone app.listen(tryPort) if no 'const listener' pattern
if (!content.includes("server.listen(tryPort)")) {
content = content.replace(
/app\.listen\(tryPort\)/,
"server.listen(tryPort)"
);
}
} else {
content = content.replace(/app\.listen\(port[\s\S]*?\}\);?\n?/m, "");
if (!content.includes("server.listen(port")) {
content += "\n" + newListenBlock.trim() + "\n";
}
}
writeIndex(content);
}
export function insertBeforeRoutes(codeBlock) {
let content = readIndex();
// Insert before startServer() or the start server section
const markers = [
"// ── Start Server",
"// ── Helpers",
"startServer(",
];
let inserted = false;
for (const marker of markers) {
const idx = content.indexOf(marker);
if (idx !== -1) {
content =
content.slice(0, idx) +
codeBlock.trim() +
"\n\n" +
content.slice(idx);
inserted = true;
break;
}
}
if (!inserted) {
// Fallback: before first app.use that isn't middleware
const routeUseMatch = content.match(/app\.use\(['"]\/(?!_dev)/);
if (routeUseMatch) {
const idx = content.indexOf(routeUseMatch[0]);
content =
content.slice(0, idx) +
codeBlock.trim() +
"\n\n" +
content.slice(idx);
} else {
content += "\n" + codeBlock.trim() + "\n";
}
}
writeIndex(content);
}
export { readIndex, writeIndex, getIndexPath };