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 +23 -12
- package/dist/index.js +89 -70
- package/dist/templates/default/README.md +3 -0
- package/dist/templates/default/docs/index.html +8 -0
- package/dist/templates/default/eslint.config.js +18 -0
- package/dist/templates/default/index.ts +7 -1
- package/dist/templates/default/package.json +9 -1
- package/package.json +6 -2
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
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
bun create disposabl-app@latest
|
|
5
|
+
# or
|
|
6
|
+
npx create-disposabl-app@latest my-app
|
|
9
7
|
```
|
|
10
8
|
|
|
11
|
-
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
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(`
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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((
|
|
42
|
-
const
|
|
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
|
-
|
|
48
|
-
|
|
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
|
-
|
|
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;
|
|
@@ -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
|
+
"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
|
}
|