servcraft 0.4.8 → 0.4.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ROADMAP.md +2 -1
- package/dist/cli/index.cjs +102 -24
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +102 -24
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/commands/add-module.ts +111 -6
- package/src/cli/commands/init.ts +77 -20
package/ROADMAP.md
CHANGED
|
@@ -4,7 +4,8 @@ This document outlines the planned features and improvements for Servcraft.
|
|
|
4
4
|
|
|
5
5
|
## Version History
|
|
6
6
|
|
|
7
|
-
- **v0.4.
|
|
7
|
+
- **v0.4.9** (Current) - Flexible JS module system (ESM/CommonJS + .js/.cjs) - Phase 3 in progress 🚧
|
|
8
|
+
- **v0.4.8** - Automatic module installation during init
|
|
8
9
|
- **v0.4.7** - CLI header alignment fix
|
|
9
10
|
- **v0.4.6** - Improved CLI design
|
|
10
11
|
- **v0.4.5** - Lazy Prisma client initialization
|
package/dist/cli/index.cjs
CHANGED
|
@@ -1949,7 +1949,7 @@ async function findServercraftModules() {
|
|
|
1949
1949
|
}
|
|
1950
1950
|
return null;
|
|
1951
1951
|
}
|
|
1952
|
-
async function generateModuleFiles(moduleName, moduleDir) {
|
|
1952
|
+
async function generateModuleFiles(moduleName, moduleDir, language = "typescript", moduleSystem = "esm", fileExtension = "ts") {
|
|
1953
1953
|
const moduleNameMap = {
|
|
1954
1954
|
users: "user",
|
|
1955
1955
|
"rate-limit": "rate-limit",
|
|
@@ -1962,7 +1962,8 @@ async function generateModuleFiles(moduleName, moduleDir) {
|
|
|
1962
1962
|
if (servercraftModulesDir) {
|
|
1963
1963
|
const sourceModuleDir = import_path3.default.join(servercraftModulesDir, sourceDirName);
|
|
1964
1964
|
if (await fileExists(sourceModuleDir)) {
|
|
1965
|
-
|
|
1965
|
+
const jsExt = language === "javascript" ? fileExtension : "js";
|
|
1966
|
+
await copyModuleFromSource(sourceModuleDir, moduleDir, language, moduleSystem, jsExt);
|
|
1966
1967
|
return;
|
|
1967
1968
|
}
|
|
1968
1969
|
}
|
|
@@ -1989,16 +1990,48 @@ async function generateModuleFiles(moduleName, moduleDir) {
|
|
|
1989
1990
|
await generateGenericModule(moduleDir, moduleName);
|
|
1990
1991
|
}
|
|
1991
1992
|
}
|
|
1992
|
-
|
|
1993
|
+
function convertESMtoCommonJS(content) {
|
|
1994
|
+
return content.replace(/^export\s+class\s+/gm, "class ").replace(/^export\s+function\s+/gm, "function ").replace(/^export\s+const\s+/gm, "const ").replace(/^export\s+let\s+/gm, "let ").replace(/^export\s+var\s+/gm, "var ").replace(
|
|
1995
|
+
/import\s*\{\s*([^}]+)\s*\}\s*from\s*['"]([^'"]+)['"]/g,
|
|
1996
|
+
"const { $1 } = require('$2')"
|
|
1997
|
+
).replace(/import\s+(\w+)\s+from\s*['"]([^'"]+)['"]/g, "const $1 = require('$2')").replace(
|
|
1998
|
+
/import\s+(\w+)\s*,\s*\{\s*([^}]+)\s*\}\s*from\s*['"]([^'"]+)['"]/g,
|
|
1999
|
+
"const $1 = require('$3');\nconst { $2 } = require('$3')"
|
|
2000
|
+
).replace(/^(class\s+(\w+)\s+\{[\s\S]*?\n\})/gm, "$1\nmodule.exports.$2 = $2;").replace(/export\s*\{\s*([^}]+)\s*\}/g, (match, exports2) => {
|
|
2001
|
+
const items = exports2.split(",").map((item) => item.trim()).filter(Boolean);
|
|
2002
|
+
return items.map((item) => `module.exports.${item} = ${item};`).join("\n");
|
|
2003
|
+
});
|
|
2004
|
+
}
|
|
2005
|
+
async function copyModuleFromSource(sourceDir, targetDir, language = "typescript", moduleSystem = "esm", fileExtension = "js") {
|
|
1993
2006
|
const entries = await fs4.readdir(sourceDir, { withFileTypes: true });
|
|
1994
2007
|
for (const entry of entries) {
|
|
1995
2008
|
const sourcePath = import_path3.default.join(sourceDir, entry.name);
|
|
1996
|
-
|
|
2009
|
+
let targetPath = import_path3.default.join(targetDir, entry.name);
|
|
1997
2010
|
if (entry.isDirectory()) {
|
|
1998
2011
|
await fs4.mkdir(targetPath, { recursive: true });
|
|
1999
|
-
await copyModuleFromSource(sourcePath, targetPath);
|
|
2012
|
+
await copyModuleFromSource(sourcePath, targetPath, language, moduleSystem, fileExtension);
|
|
2000
2013
|
} else {
|
|
2001
|
-
|
|
2014
|
+
if (language === "javascript" && entry.name.endsWith(".ts")) {
|
|
2015
|
+
const ext = `.${fileExtension}`;
|
|
2016
|
+
targetPath = targetPath.replace(/\.ts$/, ext);
|
|
2017
|
+
let content = await fs4.readFile(sourcePath, "utf-8");
|
|
2018
|
+
for (let i = 0; i < 3; i++) {
|
|
2019
|
+
content = content.replace(/import\s+type\s+\{[^}]+\}\s+from\s+['"][^'"]+['"];?\s*\n/g, "").replace(/import\s+\{([^}]+)\}\s+from/g, (match, imports) => {
|
|
2020
|
+
const filtered = imports.split(",").map((imp) => imp.trim()).filter((imp) => !imp.startsWith("type ")).join(", ");
|
|
2021
|
+
return filtered ? `import {${filtered}} from` : "";
|
|
2022
|
+
}).replace(/from\s+['"](.+?)\.js['"]/g, `from '$1${ext}'`).replace(/\b(private|public|protected|readonly)\s+/g, "").replace(
|
|
2023
|
+
/:\s*[A-Z]\w+(<[^>]+>)?(\[\])?(\s*[|&]\s*[A-Z]\w+(<[^>]+>)?(\[\])?)*(?=[,)\s=\n])/g,
|
|
2024
|
+
""
|
|
2025
|
+
).replace(/(\w+)\s*:\s*[^,)=\n]+([,)])/g, "$1$2").replace(/(\w+)\s*:\s*[^=\n{]+(\s*=)/g, "$1$2").replace(/\)\s*:\s*[^{=\n]+\s*([{=])/g, ") $1").replace(/^export\s+(interface|type)\s+[^;]+;?\s*$/gm, "").replace(/^(interface|type)\s+[^;]+;?\s*$/gm, "").replace(/\s+as\s+\w+/g, "").replace(/<[A-Z][\w,\s<>[\]|&]*>/g, "");
|
|
2026
|
+
}
|
|
2027
|
+
content = content.replace(/^\s*\n/gm, "");
|
|
2028
|
+
if (moduleSystem === "commonjs") {
|
|
2029
|
+
content = convertESMtoCommonJS(content);
|
|
2030
|
+
}
|
|
2031
|
+
await fs4.writeFile(targetPath, content, "utf-8");
|
|
2032
|
+
} else {
|
|
2033
|
+
await fs4.copyFile(sourcePath, targetPath);
|
|
2034
|
+
}
|
|
2002
2035
|
}
|
|
2003
2036
|
}
|
|
2004
2037
|
}
|
|
@@ -2139,13 +2172,13 @@ var initCommand = new import_commander2.Command("init").alias("new").description
|
|
|
2139
2172
|
console.log(import_chalk6.default.cyan("\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E"));
|
|
2140
2173
|
console.log(import_chalk6.default.cyan("\u2502") + " " + import_chalk6.default.cyan("\u2502"));
|
|
2141
2174
|
console.log(
|
|
2142
|
-
import_chalk6.default.cyan("\u2502") +
|
|
2175
|
+
import_chalk6.default.cyan("\u2502") + import_chalk6.default.bold.white("\u{1F680} Servcraft") + import_chalk6.default.gray(" - Project Generator") + " " + import_chalk6.default.cyan("\u2502")
|
|
2143
2176
|
);
|
|
2144
2177
|
console.log(
|
|
2145
|
-
import_chalk6.default.cyan("\u2502") + "
|
|
2178
|
+
import_chalk6.default.cyan("\u2502") + " " + import_chalk6.default.gray("by ") + import_chalk6.default.blue("Yao Logan") + import_chalk6.default.gray(" (@Le-Sourcier)") + " " + import_chalk6.default.cyan("\u2502")
|
|
2146
2179
|
);
|
|
2147
2180
|
console.log(
|
|
2148
|
-
import_chalk6.default.cyan("\u2502") + "
|
|
2181
|
+
import_chalk6.default.cyan("\u2502") + " " + import_chalk6.default.bgBlue.white(" in/yao-logan ") + " " + import_chalk6.default.cyan("\u2502")
|
|
2149
2182
|
);
|
|
2150
2183
|
console.log(import_chalk6.default.cyan("\u2502") + " " + import_chalk6.default.cyan("\u2502"));
|
|
2151
2184
|
console.log(import_chalk6.default.cyan("\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F"));
|
|
@@ -2153,17 +2186,24 @@ var initCommand = new import_commander2.Command("init").alias("new").description
|
|
|
2153
2186
|
let options;
|
|
2154
2187
|
if (cmdOptions?.yes) {
|
|
2155
2188
|
const db = cmdOptions.db || "postgresql";
|
|
2189
|
+
const language = cmdOptions.javascript ? "javascript" : "typescript";
|
|
2190
|
+
const moduleSystem = cmdOptions.commonjs ? "commonjs" : "esm";
|
|
2191
|
+
let fileExtension = "ts";
|
|
2192
|
+
if (language === "javascript") {
|
|
2193
|
+
fileExtension = moduleSystem === "commonjs" ? "cjs" : "js";
|
|
2194
|
+
}
|
|
2156
2195
|
options = {
|
|
2157
2196
|
name: name || "my-servcraft-app",
|
|
2158
|
-
language
|
|
2159
|
-
moduleSystem
|
|
2197
|
+
language,
|
|
2198
|
+
moduleSystem,
|
|
2199
|
+
fileExtension,
|
|
2160
2200
|
database: db,
|
|
2161
2201
|
orm: db === "mongodb" ? "mongoose" : db === "none" ? "none" : "prisma",
|
|
2162
2202
|
validator: "zod",
|
|
2163
2203
|
features: ["auth", "users", "email"]
|
|
2164
2204
|
};
|
|
2165
2205
|
} else {
|
|
2166
|
-
const
|
|
2206
|
+
const basicAnswers = await import_inquirer2.default.prompt([
|
|
2167
2207
|
{
|
|
2168
2208
|
type: "input",
|
|
2169
2209
|
name: "name",
|
|
@@ -2185,17 +2225,43 @@ var initCommand = new import_commander2.Command("init").alias("new").description
|
|
|
2185
2225
|
{ name: " JavaScript", value: "javascript" }
|
|
2186
2226
|
],
|
|
2187
2227
|
default: "typescript"
|
|
2188
|
-
}
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2228
|
+
}
|
|
2229
|
+
]);
|
|
2230
|
+
let moduleSystem = "esm";
|
|
2231
|
+
let fileExtension = "ts";
|
|
2232
|
+
if (basicAnswers.language === "javascript") {
|
|
2233
|
+
const jsConfigAnswers = await import_inquirer2.default.prompt([
|
|
2234
|
+
{
|
|
2235
|
+
type: "list",
|
|
2236
|
+
name: "moduleSystem",
|
|
2237
|
+
message: "\u{1F4E6} Select module syntax:",
|
|
2238
|
+
choices: [
|
|
2239
|
+
{ name: "\u2728 ESM (import/export)", value: "esm" },
|
|
2240
|
+
{ name: " CommonJS (require/module.exports)", value: "commonjs" }
|
|
2241
|
+
],
|
|
2242
|
+
default: "esm"
|
|
2243
|
+
},
|
|
2244
|
+
{
|
|
2245
|
+
type: "list",
|
|
2246
|
+
name: "fileExtension",
|
|
2247
|
+
message: "\u{1F4C4} Select file extension:",
|
|
2248
|
+
choices: (answers2) => {
|
|
2249
|
+
if (answers2.moduleSystem === "esm") {
|
|
2250
|
+
return [{ name: "\u2728 .js (standard for ESM)", value: "js" }];
|
|
2251
|
+
} else {
|
|
2252
|
+
return [
|
|
2253
|
+
{ name: "\u2728 .cjs (explicit CommonJS)", value: "cjs" },
|
|
2254
|
+
{ name: " .js (CommonJS in .js)", value: "js" }
|
|
2255
|
+
];
|
|
2256
|
+
}
|
|
2257
|
+
},
|
|
2258
|
+
default: (answers2) => answers2.moduleSystem === "esm" ? "js" : "cjs"
|
|
2259
|
+
}
|
|
2260
|
+
]);
|
|
2261
|
+
moduleSystem = jsConfigAnswers.moduleSystem;
|
|
2262
|
+
fileExtension = jsConfigAnswers.fileExtension;
|
|
2263
|
+
}
|
|
2264
|
+
const restAnswers = await import_inquirer2.default.prompt([
|
|
2199
2265
|
{
|
|
2200
2266
|
type: "list",
|
|
2201
2267
|
name: "database",
|
|
@@ -2234,6 +2300,12 @@ var initCommand = new import_commander2.Command("init").alias("new").description
|
|
|
2234
2300
|
]
|
|
2235
2301
|
}
|
|
2236
2302
|
]);
|
|
2303
|
+
const answers = {
|
|
2304
|
+
...basicAnswers,
|
|
2305
|
+
moduleSystem,
|
|
2306
|
+
fileExtension,
|
|
2307
|
+
...restAnswers
|
|
2308
|
+
};
|
|
2237
2309
|
const db = answers.database;
|
|
2238
2310
|
options = {
|
|
2239
2311
|
...answers,
|
|
@@ -2339,7 +2411,13 @@ var initCommand = new import_commander2.Command("init").alias("new").description
|
|
|
2339
2411
|
moduleSpinner.text = `Installing ${feature} module...`;
|
|
2340
2412
|
const moduleDir = import_path4.default.join(projectDir, "src/modules", feature);
|
|
2341
2413
|
await ensureDir(moduleDir);
|
|
2342
|
-
await generateModuleFiles(
|
|
2414
|
+
await generateModuleFiles(
|
|
2415
|
+
feature,
|
|
2416
|
+
moduleDir,
|
|
2417
|
+
options.language,
|
|
2418
|
+
options.moduleSystem,
|
|
2419
|
+
options.fileExtension
|
|
2420
|
+
);
|
|
2343
2421
|
}
|
|
2344
2422
|
moduleSpinner.succeed(`${options.features.length} module(s) installed!`);
|
|
2345
2423
|
} catch (err) {
|