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 +27 -4
- package/dist/index.js +127 -0
- package/dist/templates/default/README.md +12 -0
- package/dist/templates/default/docs/index.html +8 -0
- package/dist/templates/default/eslint.config.js +18 -0
- package/dist/templates/default/gitignore +4 -0
- package/dist/templates/default/index.ts +14 -0
- package/dist/templates/default/package.json +17 -0
- package/package.json +9 -8
- package/index.js +0 -56
package/README.md
CHANGED
|
@@ -1,11 +1,34 @@
|
|
|
1
1
|
# Create Disposabl app
|
|
2
2
|
|
|
3
|
-
|
|
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
|
|
7
|
-
|
|
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
|
-
|
|
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,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,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.
|
|
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
|
-
"
|
|
16
|
+
"dist",
|
|
17
17
|
"LICENSE"
|
|
18
18
|
],
|
|
19
19
|
"engines": {
|
|
20
|
-
"
|
|
20
|
+
"node": ">=22.12.0"
|
|
21
21
|
},
|
|
22
22
|
"scripts": {
|
|
23
|
-
"
|
|
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
|
-
}
|