create-crust 0.0.5 → 0.0.7

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
@@ -8,11 +8,13 @@ Scaffold a new [Crust](https://crustjs.com) CLI project in seconds.
8
8
  bun create crust my-cli
9
9
  ```
10
10
 
11
- This will prompt for project details and generate a ready-to-go project with:
11
+ This will prompt for your project directory, install dependencies, and optionally initialize a git repository. The package name is inferred from the directory name. The generated project includes:
12
12
 
13
13
  - `src/cli.ts` — entry point with a sample command
14
14
  - `package.json` — configured with `crust build` and `bun run` dev scripts
15
15
  - `tsconfig.json` — strict TypeScript config
16
+ - `README.md` — getting started instructions
17
+ - `.gitignore` — sensible defaults for Node/Bun projects
16
18
 
17
19
  ## Documentation
18
20
 
package/dist/index.js CHANGED
@@ -2,97 +2,11 @@
2
2
  // @bun
3
3
 
4
4
  // src/index.ts
5
- import { existsSync, mkdirSync, writeFileSync } from "fs";
5
+ import { existsSync } from "fs";
6
6
  import { basename, resolve } from "path";
7
- import { createInterface } from "readline/promises";
8
- function templatePackageJson(name, description, author) {
9
- const pkg = {
10
- name,
11
- version: "0.0.0",
12
- type: "module",
13
- bin: {
14
- [name]: "dist/cli.js"
15
- },
16
- scripts: {
17
- build: "crust build",
18
- dev: "bun run src/cli.ts"
19
- },
20
- dependencies: {
21
- "@crustjs/crust": "latest"
22
- },
23
- devDependencies: {
24
- typescript: "^5"
25
- }
26
- };
27
- if (description) {
28
- pkg.description = description;
29
- }
30
- if (author) {
31
- pkg.author = author;
32
- }
33
- return JSON.stringify(pkg, null, 2);
34
- }
35
- function templateTsconfig() {
36
- return JSON.stringify({
37
- compilerOptions: {
38
- lib: ["ESNext"],
39
- target: "ESNext",
40
- module: "Preserve",
41
- moduleDetection: "force",
42
- moduleResolution: "bundler",
43
- allowImportingTsExtensions: true,
44
- verbatimModuleSyntax: true,
45
- noEmit: true,
46
- strict: true,
47
- skipLibCheck: true,
48
- noFallthroughCasesInSwitch: true,
49
- noUncheckedIndexedAccess: true
50
- },
51
- include: ["src"]
52
- }, null, 2);
53
- }
54
- function templateCliTs(name) {
55
- return `#!/usr/bin/env bun
56
-
57
- import { defineCommand, helpPlugin, runMain, versionPlugin } from "@crustjs/crust";
58
- import pkg from "../package.json";
59
-
60
- const main = defineCommand({
61
- meta: {
62
- name: "${name}",
63
- description: "A CLI built with Crust",
64
- },
65
- args: [
66
- {
67
- name: "name",
68
- type: "string",
69
- description: "Your name",
70
- default: "world",
71
- },
72
- ],
73
- flags: {
74
- greet: {
75
- type: "string",
76
- description: "Greeting to use",
77
- default: "Hello",
78
- alias: "g",
79
- },
80
- },
81
- run({ args, flags }) {
82
- console.log(\`\${flags.greet}, \${args.name}!\`);
83
- },
84
- });
85
-
86
- runMain(main, {
87
- plugins: [versionPlugin(pkg.version), helpPlugin()],
88
- });
89
- `;
90
- }
91
- async function prompt(rl, question, defaultValue) {
92
- const suffix = defaultValue ? ` (${defaultValue})` : "";
93
- const answer = await rl.question(`${question}${suffix}: `);
94
- return answer.trim() || defaultValue;
95
- }
7
+ import { defineCommand, runMain } from "@crustjs/core";
8
+ import { detectPackageManager, runSteps, scaffold } from "@crustjs/create";
9
+ import { confirm, input, spinner } from "@crustjs/prompts";
96
10
  var INVALID_NAME_CHARS = /[<>:"|?*\\]/;
97
11
  function validateProjectName(name) {
98
12
  if (!name) {
@@ -101,70 +15,74 @@ function validateProjectName(name) {
101
15
  if (INVALID_NAME_CHARS.test(name)) {
102
16
  return `Project name contains invalid characters: ${name}`;
103
17
  }
104
- return null;
18
+ return true;
105
19
  }
106
- function scaffold(options) {
107
- const { dir, name, description, author } = options;
108
- mkdirSync(resolve(dir, "src"), { recursive: true });
109
- writeFileSync(resolve(dir, "package.json"), `${templatePackageJson(name, description, author)}
110
- `);
111
- writeFileSync(resolve(dir, "tsconfig.json"), `${templateTsconfig()}
112
- `);
113
- writeFileSync(resolve(dir, "src", "cli.ts"), templateCliTs(name));
114
- }
115
- async function main(argv = process.argv.slice(2)) {
116
- const rl = createInterface({
117
- input: process.stdin,
118
- output: process.stdout
119
- });
120
- try {
121
- let targetDir = argv[0];
122
- if (!targetDir) {
123
- targetDir = await prompt(rl, "Project directory", "my-cli");
20
+ var command = defineCommand({
21
+ meta: {
22
+ name: "create-crust",
23
+ description: "Scaffold a new Crust CLI project"
24
+ },
25
+ args: [
26
+ {
27
+ name: "directory",
28
+ type: "string",
29
+ description: "Project directory to scaffold into"
124
30
  }
31
+ ],
32
+ async run({ args }) {
33
+ const targetDir = args.directory ?? await input({
34
+ message: "Project directory",
35
+ placeholder: "my-cli",
36
+ validate: validateProjectName
37
+ });
125
38
  const resolvedDir = resolve(process.cwd(), targetDir);
126
39
  const dirName = basename(resolvedDir);
127
- if (existsSync(resolvedDir)) {
128
- const answer = await prompt(rl, `Directory "${dirName}" already exists. Overwrite?`, "no");
129
- if (answer.toLowerCase() !== "yes" && answer.toLowerCase() !== "y") {
40
+ if (targetDir !== "." && existsSync(resolvedDir)) {
41
+ const overwrite = await confirm({
42
+ message: `Directory "${dirName}" already exists. Overwrite?`,
43
+ default: false
44
+ });
45
+ if (!overwrite) {
130
46
  console.log("Aborted.");
131
47
  return;
132
48
  }
133
49
  }
134
- const name = await prompt(rl, "Project name", dirName);
135
- const nameError = validateProjectName(name);
136
- if (nameError) {
137
- throw new Error(nameError);
50
+ const name = dirName;
51
+ await scaffold({
52
+ template: "./templates/base",
53
+ dest: resolvedDir,
54
+ context: { name },
55
+ conflict: "overwrite"
56
+ });
57
+ const installDeps = await confirm({
58
+ message: "Install dependencies?",
59
+ default: true
60
+ });
61
+ if (installDeps) {
62
+ const pm = detectPackageManager(resolvedDir);
63
+ const installCmd = pm === "npm" ? "npm install" : `${pm} install`;
64
+ await runSteps([{ type: "command", cmd: installCmd }], resolvedDir);
138
65
  }
139
- const description = await prompt(rl, "Description", "A CLI built with Crust");
140
- const author = await prompt(rl, "Author", "");
141
- scaffold({ dir: resolvedDir, name, description, author });
142
- console.log(`
143
- Installing dependencies...
144
- `);
145
- const install = Bun.spawn(["bun", "install"], {
146
- cwd: resolvedDir,
147
- stdout: "inherit",
148
- stderr: "inherit"
66
+ const initGit = await confirm({
67
+ message: "Initialize a git repository?",
68
+ default: true
149
69
  });
150
- await install.exited;
151
- const relativeDir = targetDir.startsWith("/") ? targetDir : `./${targetDir}`;
70
+ if (initGit) {
71
+ await spinner({
72
+ message: "Initializing git repository...",
73
+ task: () => runSteps([{ type: "git-init", commit: "chore: initial commit" }], resolvedDir)
74
+ });
75
+ }
152
76
  console.log(`
153
77
  Created ${name}!
154
78
  `);
155
79
  console.log("Next steps:");
156
- console.log(` cd ${relativeDir}`);
80
+ if (targetDir !== ".") {
81
+ const relativeDir = targetDir.startsWith("/") ? targetDir : `./${targetDir}`;
82
+ console.log(` cd ${relativeDir}`);
83
+ }
157
84
  console.log(" bun run dev");
158
85
  console.log(" bun run build");
159
- } finally {
160
- rl.close();
161
86
  }
162
- }
163
- var isMainModule = process.argv[1] === import.meta.filename || process.argv[1]?.endsWith("/create-crust/dist/index.js") || process.argv[1]?.endsWith("/create-crust/src/index.ts");
164
- if (isMainModule) {
165
- main();
166
- }
167
- export {
168
- scaffold,
169
- main
170
- };
87
+ });
88
+ runMain(command);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-crust",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "Scaffold a new Crust CLI project.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -24,7 +24,8 @@
24
24
  "crust"
25
25
  ],
26
26
  "files": [
27
- "dist"
27
+ "dist",
28
+ "templates"
28
29
  ],
29
30
  "publishConfig": {
30
31
  "access": "public"
@@ -38,6 +39,11 @@
38
39
  "check:types": "tsc --noEmit",
39
40
  "test": "bun test"
40
41
  },
42
+ "dependencies": {
43
+ "@crustjs/core": "0.0.6",
44
+ "@crustjs/create": "0.0.2",
45
+ "@crustjs/prompts": "0.0.1"
46
+ },
41
47
  "devDependencies": {
42
48
  "@crustjs/config": "0.0.0",
43
49
  "bunup": "^0.16.29"
@@ -0,0 +1,24 @@
1
+ # {{name}}
2
+
3
+ A CLI built with [Crust](https://crustjs.com).
4
+
5
+ ## Development
6
+
7
+ ```sh
8
+ # Run in dev mode
9
+ bun run dev
10
+
11
+ # Type-check
12
+ bun run check:types
13
+
14
+ # Build standalone executable
15
+ bun run build
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```sh
21
+ # Run the CLI
22
+ {{name}} world
23
+ {{name}} --greet Hey world
24
+ ```
@@ -0,0 +1,34 @@
1
+ # dependencies (bun install)
2
+ node_modules
3
+
4
+ # output
5
+ out
6
+ dist
7
+ *.tgz
8
+
9
+ # code coverage
10
+ coverage
11
+ *.lcov
12
+
13
+ # logs
14
+ logs
15
+ _.log
16
+ report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
17
+
18
+ # dotenv environment variable files
19
+ .env
20
+ .env.development.local
21
+ .env.test.local
22
+ .env.production.local
23
+ .env.local
24
+
25
+ # caches
26
+ .eslintcache
27
+ .cache
28
+ *.tsbuildinfo
29
+
30
+ # IntelliJ based IDEs
31
+ .idea
32
+
33
+ # Finder (MacOS) folder config
34
+ .DS_Store
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "{{name}}",
3
+ "version": "0.0.0",
4
+ "type": "module",
5
+ "description": "A CLI built with Crust",
6
+ "bin": {
7
+ "{{name}}": "dist/cli"
8
+ },
9
+ "scripts": {
10
+ "dev": "bun run src/cli.ts",
11
+ "build": "crust build",
12
+ "start": "./dist/cli",
13
+ "check:types": "tsc --noEmit"
14
+ },
15
+ "dependencies": {
16
+ "@crustjs/core": "latest",
17
+ "@crustjs/plugins": "latest"
18
+ },
19
+ "devDependencies": {
20
+ "@crustjs/crust": "latest",
21
+ "@types/bun": "latest",
22
+ "typescript": "^5"
23
+ }
24
+ }
@@ -0,0 +1,33 @@
1
+ import { defineCommand, runMain } from "@crustjs/core";
2
+ import { helpPlugin, versionPlugin } from "@crustjs/plugins";
3
+ import pkg from "../package.json";
4
+
5
+ const main = defineCommand({
6
+ meta: {
7
+ name: "{{name}}",
8
+ description: "A CLI built with Crust",
9
+ },
10
+ args: [
11
+ {
12
+ name: "name",
13
+ type: "string",
14
+ description: "Your name",
15
+ default: "world",
16
+ },
17
+ ],
18
+ flags: {
19
+ greet: {
20
+ type: "string",
21
+ description: "Greeting to use",
22
+ default: "Hello",
23
+ alias: "g",
24
+ },
25
+ },
26
+ run({ args, flags }) {
27
+ console.log(`${flags.greet}, ${args.name}!`);
28
+ },
29
+ });
30
+
31
+ runMain(main, {
32
+ plugins: [versionPlugin(pkg.version), helpPlugin()],
33
+ });
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "lib": ["ESNext"],
4
+ "target": "ESNext",
5
+ "module": "Preserve",
6
+ "moduleDetection": "force",
7
+ "moduleResolution": "bundler",
8
+ "allowImportingTsExtensions": true,
9
+ "verbatimModuleSyntax": true,
10
+ "noEmit": true,
11
+ "strict": true,
12
+ "skipLibCheck": true,
13
+ "noFallthroughCasesInSwitch": true,
14
+ "noUncheckedIndexedAccess": true
15
+ },
16
+ "include": ["src"]
17
+ }