create-disposabl-app 0.0.2 → 0.0.4

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/README.md CHANGED
@@ -1,11 +1,34 @@
1
1
  # Create Disposabl app
2
2
 
3
- Requires [Bun](https://bun.com) 1.4.4 or later.
3
+ ```sh
4
+ bun create disposabl-app@latest
5
+ # or
6
+ npx create-disposabl-app@latest my-app
7
+ ```
8
+
9
+ Choose platforms and optional features. Web is required; Docs is optional. The CLI installs dependencies with Bun, then prints the commands to start your app.
10
+
11
+ Options: `-h` / `--help`, `-v` / `--version`, `-y` / `--yes` for defaults, `--docs`, and `--skip-install`.
12
+
13
+ The CLI uses Node.js 22.12 or later. Bun-only environments can use `bunx --bun create-disposabl-app@latest`. The generated app uses Bun, ESLint, and `bun fmt`. Docs, when selected, is available at `/docs`.
14
+
15
+ ## Development
16
+
17
+ The app lives in `cli/templates/default/`. Everything outside that directory is CLI or repository tooling. `bun run build` bundles the template; generated apps receive no publishing scripts or workflows.
4
18
 
5
19
  ```sh
6
- bun create disposabl-app@latest my-app
7
- cd my-app
20
+ bun install
21
+ bun fmt
22
+ bun run lint
23
+ bun run typecheck
24
+ bun run build
8
25
  bun run dev
9
26
  ```
10
27
 
11
- Downloads the starter from [disposabl-dev/create-disposabl-app](https://github.com/disposabl-dev/create-disposabl-app), excludes the CLI and npm publishing workflow, and installs dependencies with Bun. Existing folders are never overwritten.
28
+ ## Releases
29
+
30
+ Push or merge to `main` to publish. Stable versions increment the patch automatically. Set a higher stable version in `cli/package.json` for a minor or major release. Set an explicit future version such as `0.1.0-beta.1` for a beta, incrementing it manually for each beta publication. Remove the suffix and set the intended stable version when ready.
31
+
32
+ The workflow records the actual version in a release commit, publishes to npm `latest` or `beta`, confirms availability, then creates the matching Git tag and GitHub Release. Betas become GitHub prereleases. Reruns reuse the recorded version and repair incomplete releases. No PR builds are published.
33
+
34
+ First publication only: build, run `npm login`, then `npm publish` inside `cli/` with version `0.0.1`. Later releases use npm trusted publishing without an npm token in GitHub.
package/dist/index.js ADDED
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env node
2
+
3
+ // cli/index.ts
4
+ import { spawn, spawnSync } from "node:child_process";
5
+ import {
6
+ cp,
7
+ mkdir,
8
+ readdir,
9
+ readFile,
10
+ rename,
11
+ writeFile
12
+ } from "node:fs/promises";
13
+ import { resolve } from "node:path";
14
+ import { fileURLToPath } from "node:url";
15
+ import { Command } from "commander";
16
+ import prompts from "prompts";
17
+ // cli/package.json
18
+ var version = "0.0.4";
19
+
20
+ // cli/index.ts
21
+ var program = new Command("create-disposabl-app").description("Create a Disposabl app from the bundled starter.").version(version, "-v, --version").argument("[appname]", "Name of the new app").option("-y, --yes", "Use defaults without asking questions").option("--docs", "Include Docs").option("--skip-install", "Skip bun install").helpOption("-h, --help").parse();
22
+ var validName = (name) => /^[a-z0-9][a-z0-9._-]*$/.test(name) && name.length <= 214 && !["node_modules", "favicon.ico"].includes(name);
23
+ try {
24
+ const options = program.opts();
25
+ let name = program.args[0];
26
+ let docs = Boolean(options.docs);
27
+ if (process.stdin.isTTY && !options.yes) {
28
+ const answers = await prompts([
29
+ {
30
+ type: name ? null : "text",
31
+ name: "name",
32
+ message: "What is your project named?",
33
+ initial: "my-app",
34
+ validate: (value) => validName(value) || "Use a lowercase app name without spaces."
35
+ },
36
+ {
37
+ type: "multiselect",
38
+ name: "platforms",
39
+ message: "Which platforms?",
40
+ choices: [
41
+ {
42
+ title: "Web (required)",
43
+ value: "web",
44
+ selected: true,
45
+ disabled: true
46
+ }
47
+ ],
48
+ min: 1,
49
+ warn: "Web is required.",
50
+ onRender() {
51
+ for (const choice of this.value) {
52
+ if (choice.value === "web")
53
+ choice.selected = true;
54
+ }
55
+ },
56
+ hint: "Web is required. Press Enter to continue."
57
+ },
58
+ {
59
+ type: options.docs ? null : "multiselect",
60
+ name: "features",
61
+ message: "Which features?",
62
+ choices: [{ title: "Docs", value: "docs" }],
63
+ hint: "Space to select. Enter to continue without optional features."
64
+ }
65
+ ], {
66
+ onCancel: () => {
67
+ console.log("Cancelled.");
68
+ process.exit(0);
69
+ }
70
+ });
71
+ name ??= answers.name;
72
+ docs ||= answers.features?.includes("docs") ?? false;
73
+ }
74
+ if (!name || !validName(name))
75
+ throw new Error("Provide a lowercase app name, or run with --help.");
76
+ if (!options.skipInstall && spawnSync("bun", ["--version"]).status !== 0)
77
+ throw new Error("Install Bun from https://bun.com first.");
78
+ const dir = resolve(name);
79
+ await mkdir(dir);
80
+ console.log(`
81
+ Creating a new Disposabl app in ${dir}.
82
+
83
+ Using bun.
84
+
85
+ Platform: Web
86
+ Features: ${docs ? "Docs" : "None"}
87
+ `);
88
+ const template = fileURLToPath(new URL("./templates/default", import.meta.url));
89
+ for (const file of await readdir(template)) {
90
+ if (file === "docs" && !docs)
91
+ continue;
92
+ await cp(resolve(template, file), resolve(dir, file), {
93
+ recursive: true,
94
+ force: false,
95
+ errorOnExist: true
96
+ });
97
+ }
98
+ await rename(resolve(dir, "gitignore"), resolve(dir, ".gitignore"));
99
+ const manifestPath = resolve(dir, "package.json");
100
+ const manifest = JSON.parse(await readFile(manifestPath, "utf8"));
101
+ manifest.name = name;
102
+ await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}
103
+ `);
104
+ if (!options.skipInstall) {
105
+ await new Promise((done, reject) => {
106
+ const child = spawn("bun", ["install"], {
107
+ cwd: dir,
108
+ stdio: "inherit",
109
+ env: { ...process.env, NODE_ENV: "development" }
110
+ });
111
+ child.once("error", reject);
112
+ child.once("close", (code) => code === 0 ? done() : reject(new Error(`Run bun install inside ${name} to retry.`)));
113
+ });
114
+ }
115
+ console.log(`
116
+ Success! Created ${name} at ${dir}
117
+
118
+ Get started:
119
+
120
+ cd ${name}
121
+ ${options.skipInstall ? ` bun install
122
+ ` : ""} bun run dev
123
+ `);
124
+ } catch (error) {
125
+ console.error(error instanceof Error ? error.message : String(error));
126
+ process.exitCode = 1;
127
+ }
@@ -0,0 +1,12 @@
1
+ # Disposabl app
2
+
3
+ Start the development server with [Bun](https://bun.com):
4
+
5
+ ```sh
6
+ bun run dev
7
+ ```
8
+
9
+ Open http://localhost:3000. Edit `index.ts` to build your app.
10
+
11
+ Run `bun run lint` for ESLint and `bun fmt` for formatting.
12
+ If you selected Docs, open http://localhost:3000/docs and edit `docs/index.html`.
@@ -0,0 +1,8 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <meta charset="utf-8" />
4
+ <title>Documentation</title>
5
+ <h1>Documentation</h1>
6
+ <p>Edit docs/index.html to write your app's documentation.</p>
7
+ <a href="/">Back to your app</a>
8
+ </html>
@@ -0,0 +1,18 @@
1
+ import js from "@eslint/js";
2
+ import ts from "typescript-eslint";
3
+
4
+ export default ts.config(
5
+ { ignores: ["**/dist/**", "**/node_modules/**"] },
6
+ js.configs.recommended,
7
+ ts.configs.recommended,
8
+ {
9
+ languageOptions: {
10
+ globals: {
11
+ Bun: "readonly",
12
+ process: "readonly",
13
+ console: "readonly",
14
+ URL: "readonly",
15
+ },
16
+ },
17
+ },
18
+ );
@@ -0,0 +1,4 @@
1
+ node_modules/
2
+ .env
3
+ .env.*
4
+ !.env.example
@@ -0,0 +1,14 @@
1
+ const server = Bun.serve({
2
+ port: process.env.PORT ?? 3000,
3
+ async fetch(request) {
4
+ if (new URL(request.url).pathname === "/docs") {
5
+ const page = Bun.file(new URL("./docs/index.html", import.meta.url));
6
+ return (await page.exists())
7
+ ? new Response(page)
8
+ : new Response("Not found", { status: 404 });
9
+ }
10
+ return new Response("Your Disposabl app is ready.\n");
11
+ },
12
+ });
13
+
14
+ console.log(`Your app is running at ${server.url}`);
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "disposabl-app",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "bun --hot index.ts",
8
+ "lint": "eslint ."
9
+ },
10
+ "devDependencies": {
11
+ "eslint": "10.13.0",
12
+ "@eslint/js": "10.0.1",
13
+ "typescript-eslint": "8.72.1",
14
+ "typescript": "6.0.3",
15
+ "@types/bun": "1.4.4"
16
+ }
17
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-disposabl-app",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Create a Disposabl app with Bun",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -10,22 +10,23 @@
10
10
  "directory": "cli"
11
11
  },
12
12
  "bin": {
13
- "create-disposabl-app": "index.js"
13
+ "create-disposabl-app": "dist/index.js"
14
14
  },
15
15
  "files": [
16
- "index.js",
16
+ "dist",
17
17
  "LICENSE"
18
18
  ],
19
19
  "engines": {
20
- "bun": ">=1.4.4"
20
+ "node": ">=22.12.0"
21
21
  },
22
22
  "scripts": {
23
- "test": "bun test"
24
- },
25
- "dependencies": {
26
- "giget": "3.3.1"
23
+ "build": "bun build.ts"
27
24
  },
28
25
  "publishConfig": {
29
26
  "access": "public"
27
+ },
28
+ "dependencies": {
29
+ "commander": "15.0.0",
30
+ "prompts": "2.4.2"
30
31
  }
31
32
  }
package/index.js DELETED
@@ -1,56 +0,0 @@
1
- #!/usr/bin/env bun
2
- import { mkdir, readFile, writeFile } from "node:fs/promises";
3
- import { resolve } from "node:path";
4
- import { downloadTemplate } from "giget";
5
-
6
- export async function createApp(name, source = "gh:disposabl-dev/create-disposabl-app#main") {
7
- if (!name || !/^[a-z0-9][a-z0-9._-]*$/.test(name) || name.length > 214) {
8
- throw new Error("Choose a folder name using lowercase letters, numbers, dots, underscores, or hyphens.");
9
- }
10
-
11
- const dir = resolve(name);
12
- // Claim the destination before downloading. Never overwrite an existing path.
13
- await mkdir(dir);
14
- console.log(`Creating ${name}...`);
15
- await downloadTemplate(source, {
16
- dir,
17
- force: true,
18
- ignore: (path) => path === "cli" || path.startsWith("cli/") || path === ".github/workflows/publish.yml",
19
- });
20
-
21
- const manifestPath = resolve(dir, "package.json");
22
- const manifest = JSON.parse(await readFile(manifestPath, "utf8"));
23
- manifest.name = name;
24
- manifest.private = true;
25
- await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
26
- await writeFile(resolve(dir, "README.md"), `# ${name}\n\nStart the development server:\n\n\`\`\`sh\nbun run dev\n\`\`\`\n`);
27
-
28
- const install = Bun.spawn([process.execPath, "install"], {
29
- cwd: dir,
30
- stdin: "inherit",
31
- stdout: "inherit",
32
- stderr: "inherit",
33
- });
34
- if (await install.exited !== 0) {
35
- throw new Error(`Dependencies could not be installed. Run bun install inside ${name} to retry.`);
36
- }
37
- console.log(`\nYour app is ready.\n\n cd ${name}\n bun run dev\n`);
38
- return dir;
39
- }
40
-
41
- if (import.meta.main) {
42
- const args = process.argv.slice(2);
43
- if (args.length === 1 && ["--help", "-h"].includes(args[0])) {
44
- console.log("Usage: bun create disposabl-app@latest <appname>");
45
- } else if (args.length !== 1 || args[0].startsWith("-")) {
46
- console.error("Usage: bun create disposabl-app@latest <appname>");
47
- process.exitCode = 1;
48
- } else {
49
- try {
50
- await createApp(args[0]);
51
- } catch (error) {
52
- console.error(`Could not create app: ${error.message}`);
53
- process.exitCode = 1;
54
- }
55
- }
56
- }