create-disposabl-app 0.0.3 → 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,23 +1,34 @@
1
1
  # Create Disposabl app
2
2
 
3
- Create an app with [Bun](https://bun.com):
4
-
5
3
  ```sh
6
- bun create disposabl-app@latest my-app
7
- cd my-app
8
- bun run dev
4
+ bun create disposabl-app@latest
5
+ # or
6
+ npx create-disposabl-app@latest my-app
9
7
  ```
10
8
 
11
- Or use Node.js 22 or later:
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.
12
18
 
13
19
  ```sh
14
- npx create-disposabl-app@latest my-app
15
- npx create-disposabl-app@latest -h
16
- npx create-disposabl-app@latest -v
20
+ bun install
21
+ bun fmt
22
+ bun run lint
23
+ bun run typecheck
24
+ bun run build
25
+ bun run dev
17
26
  ```
18
27
 
19
- Options: `-h` / `--help`, `-v` / `--version`, and `--skip-install`.
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.
20
31
 
21
- The starter is bundled in the package. The CLI copies only its files, installs dependencies with Bun, and prints the next commands. Existing folders are never overwritten. Installing dependencies and running the app require Bun; help, version, and `--skip-install` work without it. The starter is an `index.ts` using `Bun.serve`.
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.
22
33
 
23
- The standard CLI uses Node.js 22 or later. In a Bun-only environment, run `bunx --bun create-disposabl-app@latest my-app`.
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 CHANGED
@@ -1,9 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // cli/index.ts
4
- import { parseArgs } from "node:util";
5
-
6
- // cli/create-app.ts
7
4
  import { spawn, spawnSync } from "node:child_process";
8
5
  import {
9
6
  cp,
@@ -15,93 +12,115 @@ import {
15
12
  } from "node:fs/promises";
16
13
  import { resolve } from "node:path";
17
14
  import { fileURLToPath } from "node:url";
18
- async function createApp(name, { cwd = process.cwd(), skipInstall = false } = {}) {
19
- if (!name || !/^[a-z0-9][a-z0-9._-]*$/.test(name) || name.length > 214) {
20
- throw new Error("Choose a folder name using lowercase letters, numbers, dots, underscores, or hyphens.");
21
- }
22
- if (!skipInstall && spawnSync("bun", ["--version"]).status !== 0) {
23
- throw new Error("Install Bun from https://bun.com before creating an app.");
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;
24
73
  }
25
- const dir = resolve(cwd, name);
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);
26
79
  await mkdir(dir);
27
- console.log(`Creating ${name}...`);
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
+ `);
28
88
  const template = fileURLToPath(new URL("./templates/default", import.meta.url));
29
- await Promise.all((await readdir(template)).map((file) => cp(resolve(template, file), resolve(dir, file), {
30
- recursive: true,
31
- force: false,
32
- errorOnExist: true
33
- })));
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
+ }
34
98
  await rename(resolve(dir, "gitignore"), resolve(dir, ".gitignore"));
35
99
  const manifestPath = resolve(dir, "package.json");
36
100
  const manifest = JSON.parse(await readFile(manifestPath, "utf8"));
37
101
  manifest.name = name;
38
102
  await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}
39
103
  `);
40
- if (!skipInstall) {
41
- await new Promise((resolveInstall, reject) => {
42
- const install = spawn("bun", ["install"], {
104
+ if (!options.skipInstall) {
105
+ await new Promise((done, reject) => {
106
+ const child = spawn("bun", ["install"], {
43
107
  cwd: dir,
44
108
  stdio: "inherit",
45
109
  env: { ...process.env, NODE_ENV: "development" }
46
110
  });
47
- install.once("error", reject);
48
- install.once("close", (code) => {
49
- if (code === 0)
50
- resolveInstall();
51
- else {
52
- reject(new Error(`Dependencies could not be installed. Run bun install inside ${name} to retry.`));
53
- }
54
- });
111
+ child.once("error", reject);
112
+ child.once("close", (code) => code === 0 ? done() : reject(new Error(`Run bun install inside ${name} to retry.`)));
55
113
  });
56
114
  }
57
115
  console.log(`
58
- Your app is ready.
116
+ Success! Created ${name} at ${dir}
117
+
118
+ Get started:
59
119
 
60
120
  cd ${name}
61
- ${skipInstall ? ` bun install
121
+ ${options.skipInstall ? ` bun install
62
122
  ` : ""} bun run dev
63
123
  `);
64
- return dir;
65
- }
66
- // cli/package.json
67
- var version = "0.0.3";
68
-
69
- // cli/index.ts
70
- var help = `Usage: create-disposabl-app <appname> [options]
71
-
72
- Create a Disposabl app from the bundled starter template.
73
-
74
- Options:
75
- -h, --help Show this help message
76
- -v, --version Show the CLI version
77
- --skip-install Copy the starter without running bun install
78
-
79
- Examples:
80
- bun create disposabl-app@latest my-app
81
- npx create-disposabl-app@latest my-app
82
- npx create-disposabl-app@latest --help
83
-
84
- The generated app uses Bun. Install it from https://bun.com.
85
- `;
86
- try {
87
- const { values, positionals } = parseArgs({
88
- allowPositionals: true,
89
- options: {
90
- help: { type: "boolean", short: "h" },
91
- version: { type: "boolean", short: "v" },
92
- "skip-install": { type: "boolean" }
93
- }
94
- });
95
- if (values.help)
96
- console.log(help);
97
- else if (values.version)
98
- console.log(version);
99
- else if (positionals.length !== 1) {
100
- console.error(help);
101
- process.exitCode = 1;
102
- } else {
103
- await createApp(positionals[0], { skipInstall: values["skip-install"] });
104
- }
105
124
  } catch (error) {
106
125
  console.error(error instanceof Error ? error.message : String(error));
107
126
  process.exitCode = 1;
@@ -7,3 +7,6 @@ bun run dev
7
7
  ```
8
8
 
9
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
+ );
@@ -1,6 +1,12 @@
1
1
  const server = Bun.serve({
2
2
  port: process.env.PORT ?? 3000,
3
- fetch() {
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
+ }
4
10
  return new Response("Your Disposabl app is ready.\n");
5
11
  },
6
12
  });
@@ -4,6 +4,14 @@
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
7
- "dev": "bun --hot index.ts"
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"
8
16
  }
9
17
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-disposabl-app",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "Create a Disposabl app with Bun",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -17,12 +17,16 @@
17
17
  "LICENSE"
18
18
  ],
19
19
  "engines": {
20
- "node": ">=22"
20
+ "node": ">=22.12.0"
21
21
  },
22
22
  "scripts": {
23
23
  "build": "bun build.ts"
24
24
  },
25
25
  "publishConfig": {
26
26
  "access": "public"
27
+ },
28
+ "dependencies": {
29
+ "commander": "15.0.0",
30
+ "prompts": "2.4.2"
27
31
  }
28
32
  }