create-alepha 0.12.0
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/LICENSE +21 -0
- package/README.md +12 -0
- package/dist/index.cjs +114 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +86 -0
- package/dist/index.js.map +1 -0
- package/package.json +45 -0
- package/src/CreateAlephaCoreCommands.ts +112 -0
- package/src/index.ts +17 -0
- package/src/version.ts +7 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Nicolas Foures
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
//#region rolldown:runtime
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
12
|
+
key = keys[i];
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
14
|
+
__defProp(to, key, {
|
|
15
|
+
get: ((k) => from[k]).bind(null, key),
|
|
16
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
24
|
+
value: mod,
|
|
25
|
+
enumerable: true
|
|
26
|
+
}) : target, mod));
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
let alepha = require("alepha");
|
|
30
|
+
let node_fs_promises = require("node:fs/promises");
|
|
31
|
+
let node_path = require("node:path");
|
|
32
|
+
let node_stream = require("node:stream");
|
|
33
|
+
let node_stream_promises = require("node:stream/promises");
|
|
34
|
+
let alepha_command = require("alepha/command");
|
|
35
|
+
let alepha_logger = require("alepha/logger");
|
|
36
|
+
let tar = require("tar");
|
|
37
|
+
tar = __toESM(tar);
|
|
38
|
+
let node_fs = require("node:fs");
|
|
39
|
+
|
|
40
|
+
//#region src/CreateAlephaCoreCommands.ts
|
|
41
|
+
var CreateAlephaCoreCommands = class {
|
|
42
|
+
log = (0, alepha_logger.$logger)();
|
|
43
|
+
cli = (0, alepha.$inject)(alepha_command.CliProvider);
|
|
44
|
+
detectPackageManager() {
|
|
45
|
+
const ua = process.env.npm_config_user_agent || "";
|
|
46
|
+
if (ua.startsWith("yarn")) return "yarn";
|
|
47
|
+
if (ua.startsWith("pnpm")) return "pnpm";
|
|
48
|
+
if (ua.startsWith("bun")) return "bun";
|
|
49
|
+
return "npm";
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Download Alepha starter project from GitHub.
|
|
53
|
+
*/
|
|
54
|
+
async downloadSampleProject(targetDir) {
|
|
55
|
+
const response = await fetch("https://api.github.com/repos/feunard/alepha/tarball/main", { headers: { "User-Agent": "Alepha-CLI" } });
|
|
56
|
+
if (!response.ok) throw new alepha.AlephaError(`Failed to download: ${response.statusText}`);
|
|
57
|
+
await (0, node_stream_promises.pipeline)(node_stream.Readable.fromWeb(response.body), tar.extract({
|
|
58
|
+
cwd: targetDir,
|
|
59
|
+
strip: 3,
|
|
60
|
+
filter: (path) => {
|
|
61
|
+
const parts = path.split("/");
|
|
62
|
+
return parts.length >= 3 && parts[1] === "apps" && parts[2] === "starter";
|
|
63
|
+
}
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Called when no command is provided - shows help or creates a new project
|
|
68
|
+
*/
|
|
69
|
+
root = (0, alepha_command.$command)({
|
|
70
|
+
root: true,
|
|
71
|
+
description: "Create a new Alepha project",
|
|
72
|
+
args: alepha.t.optional(alepha.t.text({ title: "name" })),
|
|
73
|
+
summary: false,
|
|
74
|
+
handler: async ({ run: run$1, args, root }) => {
|
|
75
|
+
const name = args ?? "my-app";
|
|
76
|
+
const dest = (0, node_path.join)(root, name);
|
|
77
|
+
try {
|
|
78
|
+
await (0, node_fs_promises.access)(dest);
|
|
79
|
+
this.log.error(`Directory "${name}" already exists. Please choose a different project name.`);
|
|
80
|
+
return;
|
|
81
|
+
} catch {}
|
|
82
|
+
const pm = this.detectPackageManager();
|
|
83
|
+
await (0, node_fs_promises.mkdir)(dest, { recursive: true }).catch(() => null);
|
|
84
|
+
await run$1("Downloading sample project", () => this.downloadSampleProject(dest));
|
|
85
|
+
await run$1(`cd ${name} && ${pm} install`, { alias: "Installing dependencies" });
|
|
86
|
+
await run$1(`cd ${name} && ${pm} run lint`, { alias: "Linting code" });
|
|
87
|
+
await run$1(`cd ${name} && ${pm} run typecheck`, { alias: "Type checking" });
|
|
88
|
+
await run$1(`cd ${name} && ${pm} run test`, { alias: "Running tests" });
|
|
89
|
+
await run$1(`cd ${name} && ${pm} run build`, { alias: "Building project" });
|
|
90
|
+
this.log.info("");
|
|
91
|
+
this.log.info(`$ cd ${name} && ${pm} run dev`.trim());
|
|
92
|
+
this.log.info("");
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
//#endregion
|
|
98
|
+
//#region src/version.ts
|
|
99
|
+
const packageJson = JSON.parse((0, node_fs.readFileSync)(new URL("../package.json", require("url").pathToFileURL(__filename).href), "utf-8"));
|
|
100
|
+
const version = packageJson.version;
|
|
101
|
+
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region src/index.ts
|
|
104
|
+
const alepha$1 = alepha.Alepha.create({ env: {
|
|
105
|
+
LOG_LEVEL: "alepha.core:warn,info",
|
|
106
|
+
LOG_FORMAT: "raw",
|
|
107
|
+
CLI_NAME: "create-alepha",
|
|
108
|
+
CLI_DESCRIPTION: `Create Alepha v${version} - Create a new Alepha project.`
|
|
109
|
+
} });
|
|
110
|
+
alepha$1.with(CreateAlephaCoreCommands);
|
|
111
|
+
(0, alepha.run)(alepha$1);
|
|
112
|
+
|
|
113
|
+
//#endregion
|
|
114
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["CliProvider","AlephaError","Readable","t","run","alepha","Alepha"],"sources":["../src/CreateAlephaCoreCommands.ts","../src/version.ts","../src/index.ts"],"sourcesContent":["import { access, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { Readable } from \"node:stream\";\nimport { pipeline } from \"node:stream/promises\";\nimport { $inject, AlephaError, t } from \"alepha\";\nimport { $command, CliProvider } from \"alepha/command\";\nimport { $logger } from \"alepha/logger\";\nimport * as tar from \"tar\";\n\nexport class CreateAlephaCoreCommands {\n protected readonly log = $logger();\n protected readonly cli = $inject(CliProvider);\n\n protected detectPackageManager(): \"npm\" | \"yarn\" | \"pnpm\" | \"bun\" {\n const ua = process.env.npm_config_user_agent || \"\";\n if (ua.startsWith(\"yarn\")) return \"yarn\";\n if (ua.startsWith(\"pnpm\")) return \"pnpm\";\n if (ua.startsWith(\"bun\")) return \"bun\";\n return \"npm\";\n }\n\n /**\n * Download Alepha starter project from GitHub.\n */\n public async downloadSampleProject(targetDir: string): Promise<void> {\n const url = \"https://api.github.com/repos/feunard/alepha/tarball/main\";\n const response = await fetch(url, {\n headers: {\n \"User-Agent\": \"Alepha-CLI\",\n },\n });\n\n if (!response.ok) {\n throw new AlephaError(`Failed to download: ${response.statusText}`);\n }\n\n const tarStream = Readable.fromWeb(response.body as any);\n await pipeline(\n tarStream,\n tar.extract({\n cwd: targetDir,\n strip: 3, // Remove feunard-alepha-<hash>/apps/starter prefix\n filter: (path) => {\n const parts = path.split(\"/\");\n return (\n parts.length >= 3 && parts[1] === \"apps\" && parts[2] === \"starter\"\n );\n },\n }),\n );\n }\n\n /**\n * Called when no command is provided - shows help or creates a new project\n */\n public readonly root = $command({\n root: true,\n description: \"Create a new Alepha project\",\n args: t.optional(\n t.text({\n title: \"name\",\n }),\n ),\n summary: false,\n handler: async ({ run, args, root }) => {\n const name = args ?? \"my-app\";\n const dest = join(root, name);\n\n try {\n await access(dest);\n this.log.error(\n `Directory \"${name}\" already exists. Please choose a different project name.`,\n );\n return;\n } catch {\n // Directory does not exist, proceed\n }\n\n const pm = this.detectPackageManager();\n\n await mkdir(dest, { recursive: true }).catch(() => null);\n\n await run(\"Downloading sample project\", () =>\n this.downloadSampleProject(dest),\n );\n\n await run(`cd ${name} && ${pm} install`, {\n alias: \"Installing dependencies\",\n });\n\n await run(`cd ${name} && ${pm} run lint`, {\n alias: \"Linting code\",\n });\n\n await run(`cd ${name} && ${pm} run typecheck`, {\n alias: \"Type checking\",\n });\n\n await run(`cd ${name} && ${pm} run test`, {\n alias: \"Running tests\",\n });\n\n await run(`cd ${name} && ${pm} run build`, {\n alias: \"Building project\",\n });\n\n this.log.info(\"\");\n this.log.info(`$ cd ${name} && ${pm} run dev`.trim());\n this.log.info(\"\");\n },\n });\n}\n","import { readFileSync } from \"node:fs\";\n\nconst packageJson = JSON.parse(\n readFileSync(new URL(\"../package.json\", import.meta.url), \"utf-8\"),\n);\n\nexport const version = packageJson.version;\n","#!/usr/bin/env node\nimport { Alepha, run } from \"alepha\";\nimport { CreateAlephaCoreCommands } from \"./CreateAlephaCoreCommands.ts\";\nimport { version } from \"./version.ts\";\n\nconst alepha = Alepha.create({\n env: {\n LOG_LEVEL: \"alepha.core:warn,info\",\n LOG_FORMAT: \"raw\",\n CLI_NAME: \"create-alepha\",\n CLI_DESCRIPTION: `Create Alepha v${version} - Create a new Alepha project.`,\n },\n});\n\nalepha.with(CreateAlephaCoreCommands);\n\nrun(alepha);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AASA,IAAa,2BAAb,MAAsC;CACpC,AAAmB,kCAAe;CAClC,AAAmB,0BAAcA,2BAAY;CAE7C,AAAU,uBAAwD;EAChE,MAAM,KAAK,QAAQ,IAAI,yBAAyB;AAChD,MAAI,GAAG,WAAW,OAAO,CAAE,QAAO;AAClC,MAAI,GAAG,WAAW,OAAO,CAAE,QAAO;AAClC,MAAI,GAAG,WAAW,MAAM,CAAE,QAAO;AACjC,SAAO;;;;;CAMT,MAAa,sBAAsB,WAAkC;EAEnE,MAAM,WAAW,MAAM,MADX,4DACsB,EAChC,SAAS,EACP,cAAc,cACf,EACF,CAAC;AAEF,MAAI,CAAC,SAAS,GACZ,OAAM,IAAIC,mBAAY,uBAAuB,SAAS,aAAa;AAIrE,2CADkBC,qBAAS,QAAQ,SAAS,KAAY,EAGtD,IAAI,QAAQ;GACV,KAAK;GACL,OAAO;GACP,SAAS,SAAS;IAChB,MAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,WACE,MAAM,UAAU,KAAK,MAAM,OAAO,UAAU,MAAM,OAAO;;GAG9D,CAAC,CACH;;;;;CAMH,AAAgB,oCAAgB;EAC9B,MAAM;EACN,aAAa;EACb,MAAMC,SAAE,SACNA,SAAE,KAAK,EACL,OAAO,QACR,CAAC,CACH;EACD,SAAS;EACT,SAAS,OAAO,EAAE,YAAK,MAAM,WAAW;GACtC,MAAM,OAAO,QAAQ;GACrB,MAAM,2BAAY,MAAM,KAAK;AAE7B,OAAI;AACF,uCAAa,KAAK;AAClB,SAAK,IAAI,MACP,cAAc,KAAK,2DACpB;AACD;WACM;GAIR,MAAM,KAAK,KAAK,sBAAsB;AAEtC,qCAAY,MAAM,EAAE,WAAW,MAAM,CAAC,CAAC,YAAY,KAAK;AAExD,SAAMC,MAAI,oCACR,KAAK,sBAAsB,KAAK,CACjC;AAED,SAAMA,MAAI,MAAM,KAAK,MAAM,GAAG,WAAW,EACvC,OAAO,2BACR,CAAC;AAEF,SAAMA,MAAI,MAAM,KAAK,MAAM,GAAG,YAAY,EACxC,OAAO,gBACR,CAAC;AAEF,SAAMA,MAAI,MAAM,KAAK,MAAM,GAAG,iBAAiB,EAC7C,OAAO,iBACR,CAAC;AAEF,SAAMA,MAAI,MAAM,KAAK,MAAM,GAAG,YAAY,EACxC,OAAO,iBACR,CAAC;AAEF,SAAMA,MAAI,MAAM,KAAK,MAAM,GAAG,aAAa,EACzC,OAAO,oBACR,CAAC;AAEF,QAAK,IAAI,KAAK,GAAG;AACjB,QAAK,IAAI,KAAK,QAAQ,KAAK,MAAM,GAAG,UAAU,MAAM,CAAC;AACrD,QAAK,IAAI,KAAK,GAAG;;EAEpB,CAAC;;;;;AC5GJ,MAAM,cAAc,KAAK,gCACV,IAAI,IAAI,iEAAmC,EAAE,QAAQ,CACnE;AAED,MAAa,UAAU,YAAY;;;;ACDnC,MAAMC,WAASC,cAAO,OAAO,EAC3B,KAAK;CACH,WAAW;CACX,YAAY;CACZ,UAAU;CACV,iBAAiB,kBAAkB,QAAQ;CAC5C,EACF,CAAC;AAEFD,SAAO,KAAK,yBAAyB;gBAEjCA,SAAO"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { $inject, Alepha, AlephaError, run, t } from "alepha";
|
|
3
|
+
import { access, mkdir } from "node:fs/promises";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { Readable } from "node:stream";
|
|
6
|
+
import { pipeline } from "node:stream/promises";
|
|
7
|
+
import { $command, CliProvider } from "alepha/command";
|
|
8
|
+
import { $logger } from "alepha/logger";
|
|
9
|
+
import * as tar from "tar";
|
|
10
|
+
import { readFileSync } from "node:fs";
|
|
11
|
+
|
|
12
|
+
//#region src/CreateAlephaCoreCommands.ts
|
|
13
|
+
var CreateAlephaCoreCommands = class {
|
|
14
|
+
log = $logger();
|
|
15
|
+
cli = $inject(CliProvider);
|
|
16
|
+
detectPackageManager() {
|
|
17
|
+
const ua = process.env.npm_config_user_agent || "";
|
|
18
|
+
if (ua.startsWith("yarn")) return "yarn";
|
|
19
|
+
if (ua.startsWith("pnpm")) return "pnpm";
|
|
20
|
+
if (ua.startsWith("bun")) return "bun";
|
|
21
|
+
return "npm";
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Download Alepha starter project from GitHub.
|
|
25
|
+
*/
|
|
26
|
+
async downloadSampleProject(targetDir) {
|
|
27
|
+
const response = await fetch("https://api.github.com/repos/feunard/alepha/tarball/main", { headers: { "User-Agent": "Alepha-CLI" } });
|
|
28
|
+
if (!response.ok) throw new AlephaError(`Failed to download: ${response.statusText}`);
|
|
29
|
+
await pipeline(Readable.fromWeb(response.body), tar.extract({
|
|
30
|
+
cwd: targetDir,
|
|
31
|
+
strip: 3,
|
|
32
|
+
filter: (path) => {
|
|
33
|
+
const parts = path.split("/");
|
|
34
|
+
return parts.length >= 3 && parts[1] === "apps" && parts[2] === "starter";
|
|
35
|
+
}
|
|
36
|
+
}));
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Called when no command is provided - shows help or creates a new project
|
|
40
|
+
*/
|
|
41
|
+
root = $command({
|
|
42
|
+
root: true,
|
|
43
|
+
description: "Create a new Alepha project",
|
|
44
|
+
args: t.optional(t.text({ title: "name" })),
|
|
45
|
+
summary: false,
|
|
46
|
+
handler: async ({ run: run$1, args, root }) => {
|
|
47
|
+
const name = args ?? "my-app";
|
|
48
|
+
const dest = join(root, name);
|
|
49
|
+
try {
|
|
50
|
+
await access(dest);
|
|
51
|
+
this.log.error(`Directory "${name}" already exists. Please choose a different project name.`);
|
|
52
|
+
return;
|
|
53
|
+
} catch {}
|
|
54
|
+
const pm = this.detectPackageManager();
|
|
55
|
+
await mkdir(dest, { recursive: true }).catch(() => null);
|
|
56
|
+
await run$1("Downloading sample project", () => this.downloadSampleProject(dest));
|
|
57
|
+
await run$1(`cd ${name} && ${pm} install`, { alias: "Installing dependencies" });
|
|
58
|
+
await run$1(`cd ${name} && ${pm} run lint`, { alias: "Linting code" });
|
|
59
|
+
await run$1(`cd ${name} && ${pm} run typecheck`, { alias: "Type checking" });
|
|
60
|
+
await run$1(`cd ${name} && ${pm} run test`, { alias: "Running tests" });
|
|
61
|
+
await run$1(`cd ${name} && ${pm} run build`, { alias: "Building project" });
|
|
62
|
+
this.log.info("");
|
|
63
|
+
this.log.info(`$ cd ${name} && ${pm} run dev`.trim());
|
|
64
|
+
this.log.info("");
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region src/version.ts
|
|
71
|
+
const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
|
|
72
|
+
const version = packageJson.version;
|
|
73
|
+
|
|
74
|
+
//#endregion
|
|
75
|
+
//#region src/index.ts
|
|
76
|
+
const alepha = Alepha.create({ env: {
|
|
77
|
+
LOG_LEVEL: "alepha.core:warn,info",
|
|
78
|
+
LOG_FORMAT: "raw",
|
|
79
|
+
CLI_NAME: "create-alepha",
|
|
80
|
+
CLI_DESCRIPTION: `Create Alepha v${version} - Create a new Alepha project.`
|
|
81
|
+
} });
|
|
82
|
+
alepha.with(CreateAlephaCoreCommands);
|
|
83
|
+
run(alepha);
|
|
84
|
+
|
|
85
|
+
//#endregion
|
|
86
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["run"],"sources":["../src/CreateAlephaCoreCommands.ts","../src/version.ts","../src/index.ts"],"sourcesContent":["import { access, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { Readable } from \"node:stream\";\nimport { pipeline } from \"node:stream/promises\";\nimport { $inject, AlephaError, t } from \"alepha\";\nimport { $command, CliProvider } from \"alepha/command\";\nimport { $logger } from \"alepha/logger\";\nimport * as tar from \"tar\";\n\nexport class CreateAlephaCoreCommands {\n protected readonly log = $logger();\n protected readonly cli = $inject(CliProvider);\n\n protected detectPackageManager(): \"npm\" | \"yarn\" | \"pnpm\" | \"bun\" {\n const ua = process.env.npm_config_user_agent || \"\";\n if (ua.startsWith(\"yarn\")) return \"yarn\";\n if (ua.startsWith(\"pnpm\")) return \"pnpm\";\n if (ua.startsWith(\"bun\")) return \"bun\";\n return \"npm\";\n }\n\n /**\n * Download Alepha starter project from GitHub.\n */\n public async downloadSampleProject(targetDir: string): Promise<void> {\n const url = \"https://api.github.com/repos/feunard/alepha/tarball/main\";\n const response = await fetch(url, {\n headers: {\n \"User-Agent\": \"Alepha-CLI\",\n },\n });\n\n if (!response.ok) {\n throw new AlephaError(`Failed to download: ${response.statusText}`);\n }\n\n const tarStream = Readable.fromWeb(response.body as any);\n await pipeline(\n tarStream,\n tar.extract({\n cwd: targetDir,\n strip: 3, // Remove feunard-alepha-<hash>/apps/starter prefix\n filter: (path) => {\n const parts = path.split(\"/\");\n return (\n parts.length >= 3 && parts[1] === \"apps\" && parts[2] === \"starter\"\n );\n },\n }),\n );\n }\n\n /**\n * Called when no command is provided - shows help or creates a new project\n */\n public readonly root = $command({\n root: true,\n description: \"Create a new Alepha project\",\n args: t.optional(\n t.text({\n title: \"name\",\n }),\n ),\n summary: false,\n handler: async ({ run, args, root }) => {\n const name = args ?? \"my-app\";\n const dest = join(root, name);\n\n try {\n await access(dest);\n this.log.error(\n `Directory \"${name}\" already exists. Please choose a different project name.`,\n );\n return;\n } catch {\n // Directory does not exist, proceed\n }\n\n const pm = this.detectPackageManager();\n\n await mkdir(dest, { recursive: true }).catch(() => null);\n\n await run(\"Downloading sample project\", () =>\n this.downloadSampleProject(dest),\n );\n\n await run(`cd ${name} && ${pm} install`, {\n alias: \"Installing dependencies\",\n });\n\n await run(`cd ${name} && ${pm} run lint`, {\n alias: \"Linting code\",\n });\n\n await run(`cd ${name} && ${pm} run typecheck`, {\n alias: \"Type checking\",\n });\n\n await run(`cd ${name} && ${pm} run test`, {\n alias: \"Running tests\",\n });\n\n await run(`cd ${name} && ${pm} run build`, {\n alias: \"Building project\",\n });\n\n this.log.info(\"\");\n this.log.info(`$ cd ${name} && ${pm} run dev`.trim());\n this.log.info(\"\");\n },\n });\n}\n","import { readFileSync } from \"node:fs\";\n\nconst packageJson = JSON.parse(\n readFileSync(new URL(\"../package.json\", import.meta.url), \"utf-8\"),\n);\n\nexport const version = packageJson.version;\n","#!/usr/bin/env node\nimport { Alepha, run } from \"alepha\";\nimport { CreateAlephaCoreCommands } from \"./CreateAlephaCoreCommands.ts\";\nimport { version } from \"./version.ts\";\n\nconst alepha = Alepha.create({\n env: {\n LOG_LEVEL: \"alepha.core:warn,info\",\n LOG_FORMAT: \"raw\",\n CLI_NAME: \"create-alepha\",\n CLI_DESCRIPTION: `Create Alepha v${version} - Create a new Alepha project.`,\n },\n});\n\nalepha.with(CreateAlephaCoreCommands);\n\nrun(alepha);\n"],"mappings":";;;;;;;;;;;;AASA,IAAa,2BAAb,MAAsC;CACpC,AAAmB,MAAM,SAAS;CAClC,AAAmB,MAAM,QAAQ,YAAY;CAE7C,AAAU,uBAAwD;EAChE,MAAM,KAAK,QAAQ,IAAI,yBAAyB;AAChD,MAAI,GAAG,WAAW,OAAO,CAAE,QAAO;AAClC,MAAI,GAAG,WAAW,OAAO,CAAE,QAAO;AAClC,MAAI,GAAG,WAAW,MAAM,CAAE,QAAO;AACjC,SAAO;;;;;CAMT,MAAa,sBAAsB,WAAkC;EAEnE,MAAM,WAAW,MAAM,MADX,4DACsB,EAChC,SAAS,EACP,cAAc,cACf,EACF,CAAC;AAEF,MAAI,CAAC,SAAS,GACZ,OAAM,IAAI,YAAY,uBAAuB,SAAS,aAAa;AAIrE,QAAM,SADY,SAAS,QAAQ,SAAS,KAAY,EAGtD,IAAI,QAAQ;GACV,KAAK;GACL,OAAO;GACP,SAAS,SAAS;IAChB,MAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,WACE,MAAM,UAAU,KAAK,MAAM,OAAO,UAAU,MAAM,OAAO;;GAG9D,CAAC,CACH;;;;;CAMH,AAAgB,OAAO,SAAS;EAC9B,MAAM;EACN,aAAa;EACb,MAAM,EAAE,SACN,EAAE,KAAK,EACL,OAAO,QACR,CAAC,CACH;EACD,SAAS;EACT,SAAS,OAAO,EAAE,YAAK,MAAM,WAAW;GACtC,MAAM,OAAO,QAAQ;GACrB,MAAM,OAAO,KAAK,MAAM,KAAK;AAE7B,OAAI;AACF,UAAM,OAAO,KAAK;AAClB,SAAK,IAAI,MACP,cAAc,KAAK,2DACpB;AACD;WACM;GAIR,MAAM,KAAK,KAAK,sBAAsB;AAEtC,SAAM,MAAM,MAAM,EAAE,WAAW,MAAM,CAAC,CAAC,YAAY,KAAK;AAExD,SAAMA,MAAI,oCACR,KAAK,sBAAsB,KAAK,CACjC;AAED,SAAMA,MAAI,MAAM,KAAK,MAAM,GAAG,WAAW,EACvC,OAAO,2BACR,CAAC;AAEF,SAAMA,MAAI,MAAM,KAAK,MAAM,GAAG,YAAY,EACxC,OAAO,gBACR,CAAC;AAEF,SAAMA,MAAI,MAAM,KAAK,MAAM,GAAG,iBAAiB,EAC7C,OAAO,iBACR,CAAC;AAEF,SAAMA,MAAI,MAAM,KAAK,MAAM,GAAG,YAAY,EACxC,OAAO,iBACR,CAAC;AAEF,SAAMA,MAAI,MAAM,KAAK,MAAM,GAAG,aAAa,EACzC,OAAO,oBACR,CAAC;AAEF,QAAK,IAAI,KAAK,GAAG;AACjB,QAAK,IAAI,KAAK,QAAQ,KAAK,MAAM,GAAG,UAAU,MAAM,CAAC;AACrD,QAAK,IAAI,KAAK,GAAG;;EAEpB,CAAC;;;;;AC5GJ,MAAM,cAAc,KAAK,MACvB,aAAa,IAAI,IAAI,mBAAmB,OAAO,KAAK,IAAI,EAAE,QAAQ,CACnE;AAED,MAAa,UAAU,YAAY;;;;ACDnC,MAAM,SAAS,OAAO,OAAO,EAC3B,KAAK;CACH,WAAW;CACX,YAAY;CACZ,UAAU;CACV,iBAAiB,kBAAkB,QAAQ;CAC5C,EACF,CAAC;AAEF,OAAO,KAAK,yBAAyB;AAErC,IAAI,OAAO"}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-alepha",
|
|
3
|
+
"description": "Create a new Alepha project with a single command.",
|
|
4
|
+
"author": "Nicolas Foures",
|
|
5
|
+
"version": "0.12.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=22.0.0"
|
|
9
|
+
},
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"bin": "./dist/index.js",
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"src"
|
|
15
|
+
],
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"alepha": "0.12.0",
|
|
18
|
+
"tar": "^7.5.2"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"tsdown": "^0.16.7",
|
|
22
|
+
"vitest": "^4.0.14"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"lint": "biome check --fix",
|
|
26
|
+
"typecheck": "tsc --noEmit",
|
|
27
|
+
"test": "vitest run --passWithNoTests",
|
|
28
|
+
"build": "tsdown -c=../../tsdown.config.ts"
|
|
29
|
+
},
|
|
30
|
+
"homepage": "https://github.com/feunard/alepha",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "git+https://github.com/feunard/alepha.git"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"alepha",
|
|
37
|
+
"create",
|
|
38
|
+
"scaffold",
|
|
39
|
+
"typescript",
|
|
40
|
+
"framework"
|
|
41
|
+
],
|
|
42
|
+
"main": "./dist/index.js",
|
|
43
|
+
"module": "./dist/index.js",
|
|
44
|
+
"types": "./dist/index.d.ts"
|
|
45
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { access, mkdir } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { Readable } from "node:stream";
|
|
4
|
+
import { pipeline } from "node:stream/promises";
|
|
5
|
+
import { $inject, AlephaError, t } from "alepha";
|
|
6
|
+
import { $command, CliProvider } from "alepha/command";
|
|
7
|
+
import { $logger } from "alepha/logger";
|
|
8
|
+
import * as tar from "tar";
|
|
9
|
+
|
|
10
|
+
export class CreateAlephaCoreCommands {
|
|
11
|
+
protected readonly log = $logger();
|
|
12
|
+
protected readonly cli = $inject(CliProvider);
|
|
13
|
+
|
|
14
|
+
protected detectPackageManager(): "npm" | "yarn" | "pnpm" | "bun" {
|
|
15
|
+
const ua = process.env.npm_config_user_agent || "";
|
|
16
|
+
if (ua.startsWith("yarn")) return "yarn";
|
|
17
|
+
if (ua.startsWith("pnpm")) return "pnpm";
|
|
18
|
+
if (ua.startsWith("bun")) return "bun";
|
|
19
|
+
return "npm";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Download Alepha starter project from GitHub.
|
|
24
|
+
*/
|
|
25
|
+
public async downloadSampleProject(targetDir: string): Promise<void> {
|
|
26
|
+
const url = "https://api.github.com/repos/feunard/alepha/tarball/main";
|
|
27
|
+
const response = await fetch(url, {
|
|
28
|
+
headers: {
|
|
29
|
+
"User-Agent": "Alepha-CLI",
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
throw new AlephaError(`Failed to download: ${response.statusText}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const tarStream = Readable.fromWeb(response.body as any);
|
|
38
|
+
await pipeline(
|
|
39
|
+
tarStream,
|
|
40
|
+
tar.extract({
|
|
41
|
+
cwd: targetDir,
|
|
42
|
+
strip: 3, // Remove feunard-alepha-<hash>/apps/starter prefix
|
|
43
|
+
filter: (path) => {
|
|
44
|
+
const parts = path.split("/");
|
|
45
|
+
return (
|
|
46
|
+
parts.length >= 3 && parts[1] === "apps" && parts[2] === "starter"
|
|
47
|
+
);
|
|
48
|
+
},
|
|
49
|
+
}),
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Called when no command is provided - shows help or creates a new project
|
|
55
|
+
*/
|
|
56
|
+
public readonly root = $command({
|
|
57
|
+
root: true,
|
|
58
|
+
description: "Create a new Alepha project",
|
|
59
|
+
args: t.optional(
|
|
60
|
+
t.text({
|
|
61
|
+
title: "name",
|
|
62
|
+
}),
|
|
63
|
+
),
|
|
64
|
+
summary: false,
|
|
65
|
+
handler: async ({ run, args, root }) => {
|
|
66
|
+
const name = args ?? "my-app";
|
|
67
|
+
const dest = join(root, name);
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
await access(dest);
|
|
71
|
+
this.log.error(
|
|
72
|
+
`Directory "${name}" already exists. Please choose a different project name.`,
|
|
73
|
+
);
|
|
74
|
+
return;
|
|
75
|
+
} catch {
|
|
76
|
+
// Directory does not exist, proceed
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const pm = this.detectPackageManager();
|
|
80
|
+
|
|
81
|
+
await mkdir(dest, { recursive: true }).catch(() => null);
|
|
82
|
+
|
|
83
|
+
await run("Downloading sample project", () =>
|
|
84
|
+
this.downloadSampleProject(dest),
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
await run(`cd ${name} && ${pm} install`, {
|
|
88
|
+
alias: "Installing dependencies",
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
await run(`cd ${name} && ${pm} run lint`, {
|
|
92
|
+
alias: "Linting code",
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
await run(`cd ${name} && ${pm} run typecheck`, {
|
|
96
|
+
alias: "Type checking",
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
await run(`cd ${name} && ${pm} run test`, {
|
|
100
|
+
alias: "Running tests",
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
await run(`cd ${name} && ${pm} run build`, {
|
|
104
|
+
alias: "Building project",
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
this.log.info("");
|
|
108
|
+
this.log.info(`$ cd ${name} && ${pm} run dev`.trim());
|
|
109
|
+
this.log.info("");
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Alepha, run } from "alepha";
|
|
3
|
+
import { CreateAlephaCoreCommands } from "./CreateAlephaCoreCommands.ts";
|
|
4
|
+
import { version } from "./version.ts";
|
|
5
|
+
|
|
6
|
+
const alepha = Alepha.create({
|
|
7
|
+
env: {
|
|
8
|
+
LOG_LEVEL: "alepha.core:warn,info",
|
|
9
|
+
LOG_FORMAT: "raw",
|
|
10
|
+
CLI_NAME: "create-alepha",
|
|
11
|
+
CLI_DESCRIPTION: `Create Alepha v${version} - Create a new Alepha project.`,
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
alepha.with(CreateAlephaCoreCommands);
|
|
16
|
+
|
|
17
|
+
run(alepha);
|