create-rolldown 0.0.0 → 0.0.2

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.
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025-PRESENT Sunny-117 <https://github.com/Sunny-117>
3
+ Copyright (c) 2026 Sunny-117
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,26 +1,288 @@
1
1
  # create-rolldown
2
2
 
3
- [![npm version][npm-version-src]][npm-version-href]
4
- [![npm downloads][npm-downloads-src]][npm-downloads-href]
5
- [![bundle][bundle-src]][bundle-href]
6
- [![JSDocs][jsdocs-src]][jsdocs-href]
7
- [![License][license-src]][license-href]
3
+ [![npm version](https://img.shields.io/npm/v/create-rolldown.svg)](https://www.npmjs.com/package/create-rolldown)
4
+ [![license](https://img.shields.io/npm/l/create-rolldown.svg)](https://github.com/rolldown/create-rolldown/blob/main/LICENSE)
8
5
 
9
- _description_
6
+ Scaffolding tool for [Rolldown](https://rolldown.rs) library projects - a fast JavaScript bundler written in Rust.
7
+
8
+ ## Features
9
+
10
+ - 🚀 **Fast Setup** - Create a new Rolldown project in seconds
11
+ - 🎨 **TypeScript First** - All templates use TypeScript by default
12
+ - 📦 **Library Development Focus** - Templates designed for building and publishing JavaScript/TypeScript libraries, component libraries, and utility packages
13
+ - 🎮 **Playground Included** - Framework templates include a Vite-powered playground for development and testing
14
+ - 🔧 **Interactive & Non-Interactive Modes** - Flexible usage for both manual and automated workflows
15
+ - 📦 **Smart Package Manager Detection** - Automatically detects and uses your preferred package manager (npm, pnpm, yarn, bun)
16
+ - ⚡ **Immediate Start** - Optional flag to install dependencies and start playground immediately
17
+
18
+ ## Usage
19
+
20
+ ### Interactive Mode (Recommended)
21
+
22
+ Simply run one of the following commands and follow the prompts:
23
+
24
+ ```bash
25
+ # npm
26
+ npm create rolldown@latest
27
+
28
+ # pnpm
29
+ pnpm create rolldown
30
+
31
+ # yarn
32
+ yarn create rolldown
33
+
34
+ # bun
35
+ bun create rolldown
36
+ ```
37
+
38
+ You'll be prompted to:
39
+
40
+ 1. Enter a project name
41
+ 2. Choose a framework (Vanilla, React, Vue, Solid, or Svelte)
42
+ 3. Optionally install dependencies and start the playground immediately
43
+
44
+ > **Note**: All templates use TypeScript and are designed for library development (utility libraries, component libraries, tools, etc.).
45
+
46
+ ### Non-Interactive Mode
47
+
48
+ For automated workflows or CI/CD pipelines:
49
+
50
+ ```bash
51
+ # Create a project with all options specified
52
+ npm create rolldown@latest my-lib -- --template react --no-interactive
53
+
54
+ # With immediate install and start
55
+ npm create rolldown@latest my-lib -- --template vue --immediate --no-interactive
56
+
57
+ # Overwrite existing directory
58
+ npm create rolldown@latest my-lib -- --template solid --overwrite --no-interactive
59
+ ```
60
+
61
+ ## Command Line Options
62
+
63
+ ```
64
+ Usage: create-rolldown [project-name] [options]
65
+
66
+ Options:
67
+ -t, --template <template> Specify a template (vanilla, react, vue, solid, svelte)
68
+ --overwrite Overwrite existing files in target directory
69
+ -i, --immediate Install dependencies and start playground immediately
70
+ --interactive Force interactive mode (default in TTY)
71
+ --no-interactive Force non-interactive mode (default in non-TTY)
72
+ -h, --help Display this help message
73
+
74
+ Available templates:
75
+ vanilla Vanilla TypeScript library
76
+ react React component library
77
+ vue Vue component library
78
+ solid SolidJS component library
79
+ svelte Svelte component library
80
+ ```
81
+
82
+ ## Examples
83
+
84
+ ### Create a React library (components, hooks, utilities)
85
+
86
+ ```bash
87
+ npm create rolldown@latest my-react-lib
88
+ # Select "react"
89
+ ```
90
+
91
+ ### Create a utility library and start immediately
92
+
93
+ ```bash
94
+ npm create rolldown@latest my-utils -- --template vanilla --immediate
95
+ ```
96
+
97
+ ### Create a Vue composables library in CI/CD
98
+
99
+ ```bash
100
+ npm create rolldown@latest my-vue-composables -- --template vue --no-interactive
101
+ ```
102
+
103
+ ## Supported Templates
104
+
105
+ | Template | Description | Use Cases | Playground |
106
+ | --------- | -------------------------------- | ---------------------------------- | ---------- |
107
+ | `vanilla` | Vanilla TypeScript library | Utility libraries, tools, helpers | ❌ |
108
+ | `react` | React library with TypeScript | React components, hooks, utilities | ✅ Vite |
109
+ | `vue` | Vue 3 library with TypeScript | Vue components, composables | ✅ Vite |
110
+ | `solid` | SolidJS library with TypeScript | Solid components, primitives | ✅ Vite |
111
+ | `svelte` | Svelte 5 library with TypeScript | Svelte components, actions | ✅ Vite |
112
+
113
+ ### Template Architecture
114
+
115
+ **Vanilla Template** - For pure TypeScript/JavaScript libraries:
116
+
117
+ ```
118
+ your-library/
119
+ ├── src/
120
+ │ └── index.ts # Main entry point
121
+ ├── dist/ # Build output (generated)
122
+ ├── rolldown.config.ts
123
+ ├── tsconfig.json
124
+ └── package.json
125
+ ```
126
+
127
+ **Framework Templates** (React, Vue, Solid, Svelte) - For framework-specific libraries:
128
+
129
+ ```
130
+ your-library/
131
+ ├── src/ # Component library source code
132
+ │ ├── index.ts # Main entry point (exports)
133
+ │ └── MyButton.* # Example component
134
+ ├── playground/ # Development playground (Vite)
135
+ │ ├── src/
136
+ │ │ ├── App.* # Playground app
137
+ │ │ ├── index.* # Playground entry
138
+ │ │ └── style.css # Playground styles
139
+ │ ├── index.html
140
+ │ └── public/
141
+ ├── dist/ # Build output (generated)
142
+ ├── rolldown.config.js # Rolldown configuration
143
+ ├── vite.config.ts # Vite configuration (for playground)
144
+ ├── tsconfig.json
145
+ ├── package.json
146
+ └── README.md
147
+ ```
148
+
149
+ **Key Features:**
150
+
151
+ - `src/` - Your library source code (built with Rolldown)
152
+ - `playground/` - Development environment (powered by Vite with HMR)
153
+ - `npm run build` - Build library with Rolldown
154
+ - `npm run dev` - Watch mode for library development
155
+ - `npm run play` - Start Vite playground for testing your library
156
+ - Ready for npm publishing with proper exports configuration
157
+ - Perfect for component libraries, utility libraries, hooks, composables, and more
158
+
159
+ ## Development
160
+
161
+ ### Prerequisites
162
+
163
+ - Node.js 20.19.0+ or 22.12.0+
164
+ - pnpm (recommended) or npm
165
+
166
+ ### Setup
167
+
168
+ ```bash
169
+ # Clone the repository
170
+ git clone https://github.com/rolldown/create-rolldown.git
171
+ cd create-rolldown
172
+
173
+ # Install dependencies
174
+ pnpm install
175
+
176
+ # Run in development mode (watch mode)
177
+ pnpm dev
178
+
179
+ # Build for production
180
+ pnpm build
181
+
182
+ # Run tests
183
+ pnpm test
184
+
185
+ # Run tests in watch mode
186
+ pnpm test:watch
187
+
188
+ # Type checking
189
+ pnpm typecheck
190
+
191
+ # Linting
192
+ pnpm lint
193
+
194
+ # Format code
195
+ pnpm format
196
+
197
+ # Check formatting
198
+ pnpm format:check
199
+ ```
200
+
201
+ ### Project Structure
202
+
203
+ ```
204
+ create-rolldown/
205
+ ├── src/
206
+ │ ├── cli.ts # Main CLI entry point
207
+ │ └── utils/ # Utility modules
208
+ │ ├── args.ts # Argument parsing
209
+ │ ├── command.ts # Command execution
210
+ │ ├── constants.ts # Framework definitions
211
+ │ ├── file.ts # File operations
212
+ │ ├── package-manager.ts # Package manager detection
213
+ │ ├── prompts.ts # Interactive prompts
214
+ │ ├── types.ts # TypeScript types
215
+ │ └── validation.ts # Input validation
216
+ ├── __tests__/
217
+ │ └── cli.spec.ts # Integration tests
218
+ ├── template-vanilla/ # Vanilla TS template
219
+ ├── template-react/ # React template
220
+ ├── template-vue/ # Vue template
221
+ ├── template-solid/ # Solid template
222
+ ├── template-svelte/ # Svelte template
223
+ ├── index.js # CLI entry point
224
+ ├── package.json
225
+ └── tsconfig.json
226
+ ```
227
+
228
+ ### Testing
229
+
230
+ The project uses a comprehensive testing strategy:
231
+
232
+ - **Unit Tests**: Test specific functions and edge cases
233
+ - **Property-Based Tests**: Test universal properties across many inputs using [fast-check](https://github.com/dubzzz/fast-check)
234
+ - **Integration Tests**: Test complete CLI workflows
235
+
236
+ Run tests:
237
+
238
+ ```bash
239
+ # Run all tests once
240
+ pnpm test
241
+
242
+ # Run tests in watch mode
243
+ pnpm test:watch
244
+ ```
245
+
246
+ ### Adding a New Template
247
+
248
+ 1. Create a new directory: `template-{framework}` (e.g., `template-preact`)
249
+ 2. Add all necessary project files following the library structure:
250
+ - `src/` - Library source code
251
+ - `playground/` - Vite playground (optional, for framework templates)
252
+ - `rolldown.config.js` - Rolldown configuration
253
+ - `vite.config.ts` - Vite configuration (if playground exists)
254
+ - `package.json` - With proper exports and scripts
255
+ - `tsconfig.json` - TypeScript configuration
256
+ - `.gitignore` - Git ignore rules
257
+ - `README.md` - Template documentation
258
+ 3. Use `.gitignore` (not `_gitignore`) - it will be preserved during scaffolding
259
+ 4. Update `FRAMEWORKS` array in `src/utils/constants.ts`
260
+ 5. Test the new template with both interactive and non-interactive modes
261
+
262
+ ## How It Works
263
+
264
+ 1. **Parse CLI arguments** using `mri`
265
+ 2. **Detect mode** (interactive vs non-interactive based on TTY and flags)
266
+ 3. **Collect configuration** (project name, template, options)
267
+ 4. **Validate inputs** (package name format, directory conflicts)
268
+ 5. **Copy template files** to target directory
269
+ 6. **Update files** (package.json name, metadata)
270
+ 7. **Optionally install dependencies** and start playground
271
+
272
+ ## Requirements
273
+
274
+ - Node.js ^20.19.0 || >=22.12.0
275
+
276
+ ## Contributing
277
+
278
+ Contributions are welcome! Please feel free to submit a Pull Request.
10
279
 
11
280
  ## License
12
281
 
13
- [MIT](./LICENSE) License © [Sunny-117](https://github.com/Sunny-117)
282
+ MIT - see [LICENSE](./LICENSE) file for details
14
283
 
15
- <!-- Badges -->
284
+ ## Related Projects
16
285
 
17
- [npm-version-src]: https://img.shields.io/npm/v/create-rolldown?style=flat&colorA=080f12&colorB=1fa669
18
- [npm-version-href]: https://npmjs.com/package/create-rolldown
19
- [npm-downloads-src]: https://img.shields.io/npm/dm/create-rolldown?style=flat&colorA=080f12&colorB=1fa669
20
- [npm-downloads-href]: https://npmjs.com/package/create-rolldown
21
- [bundle-src]: https://img.shields.io/bundlephobia/minzip/create-rolldown?style=flat&colorA=080f12&colorB=1fa669&label=minzip
22
- [bundle-href]: https://bundlephobia.com/result?p=create-rolldown
23
- [license-src]: https://img.shields.io/github/license/Sunny-117/create-rolldown.svg?style=flat&colorA=080f12&colorB=1fa669
24
- [license-href]: https://github.com/Sunny-117/create-rolldown/blob/main/LICENSE
25
- [jsdocs-src]: https://img.shields.io/badge/jsdocs-reference-080f12?style=flat&colorA=080f12&colorB=1fa669
26
- [jsdocs-href]: https://www.jsdocs.io/package/create-rolldown
286
+ - [Rolldown](https://rolldown.rs) - Fast JavaScript bundler written in Rust
287
+ - [tsdown](https://tsdown.dev) - TypeScript bundler built on Rolldown
288
+ - [create-vite](https://github.com/vitejs/vite/tree/main/packages/create-vite) - Inspiration for this project
package/dist/cli.js ADDED
@@ -0,0 +1,657 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import pc from "picocolors";
5
+ import * as prompts from "@clack/prompts";
6
+ import spawn from "cross-spawn";
7
+ import mri from "mri";
8
+
9
+ //#region src/utils/constants.ts
10
+ /**
11
+ * Supported frameworks with their variants
12
+ * All templates use TypeScript and are designed for library development
13
+ * (utility libraries, component libraries, tools, hooks, composables, etc.)
14
+ */
15
+ const FRAMEWORKS = [
16
+ {
17
+ name: "vanilla",
18
+ display: "Vanilla",
19
+ color: pc.yellow
20
+ },
21
+ {
22
+ name: "react",
23
+ display: "React",
24
+ color: pc.cyan
25
+ },
26
+ {
27
+ name: "vue",
28
+ display: "Vue",
29
+ color: pc.green
30
+ },
31
+ {
32
+ name: "solid",
33
+ display: "Solid",
34
+ color: pc.blue
35
+ },
36
+ {
37
+ name: "svelte",
38
+ display: "Svelte",
39
+ color: pc.red
40
+ }
41
+ ];
42
+ /**
43
+ * All available template names (flat list)
44
+ */
45
+ const TEMPLATES = FRAMEWORKS.map((f) => f.name);
46
+ /**
47
+ * File rename mappings for special files
48
+ */
49
+ const renameFiles = { _gitignore: ".gitignore" };
50
+
51
+ //#endregion
52
+ //#region src/utils/file.ts
53
+ /**
54
+ * Check if a directory is empty (ignoring .git)
55
+ * @param path - The directory path to check
56
+ * @returns true if empty or only contains .git, false otherwise
57
+ */
58
+ function isEmpty(path$1) {
59
+ const files = fs.readdirSync(path$1);
60
+ return files.length === 0 || files.length === 1 && files[0] === ".git";
61
+ }
62
+ /**
63
+ * Empty a directory but preserve .git folder
64
+ * @param dir - The directory to empty
65
+ * @throws Error if directory emptying fails
66
+ */
67
+ function emptyDir(dir) {
68
+ if (!fs.existsSync(dir)) return;
69
+ try {
70
+ for (const file of fs.readdirSync(dir)) {
71
+ if (file === ".git") continue;
72
+ fs.rmSync(path.resolve(dir, file), {
73
+ recursive: true,
74
+ force: true
75
+ });
76
+ }
77
+ } catch (error) {
78
+ if (error instanceof Error) throw new Error(`Failed to empty directory ${dir}: ${error.message}`);
79
+ throw error;
80
+ }
81
+ }
82
+ /**
83
+ * Copy a file or directory
84
+ * @param src - Source path
85
+ * @param dest - Destination path
86
+ * @throws Error if copy operation fails
87
+ */
88
+ function copy(src, dest) {
89
+ try {
90
+ const stat = fs.statSync(src);
91
+ if (stat.isDirectory()) copyDir(src, dest);
92
+ else fs.copyFileSync(src, dest);
93
+ } catch (error) {
94
+ if (error instanceof Error) throw new Error(`Failed to copy from ${src} to ${dest}: ${error.message}`);
95
+ throw error;
96
+ }
97
+ }
98
+ /**
99
+ * Recursively copy a directory
100
+ * @param srcDir - Source directory
101
+ * @param destDir - Destination directory
102
+ * @throws Error if directory copy fails
103
+ */
104
+ function copyDir(srcDir, destDir) {
105
+ try {
106
+ fs.mkdirSync(destDir, { recursive: true });
107
+ for (const file of fs.readdirSync(srcDir)) {
108
+ const srcFile = path.resolve(srcDir, file);
109
+ const destFile = path.resolve(destDir, file);
110
+ copy(srcFile, destFile);
111
+ }
112
+ } catch (error) {
113
+ if (error instanceof Error) throw new Error(`Failed to copy directory from ${srcDir} to ${destDir}: ${error.message}`);
114
+ throw error;
115
+ }
116
+ }
117
+ /**
118
+ * Edit a file by applying a transformation function to its content
119
+ * @param file - File path to edit
120
+ * @param callback - Function that transforms the file content
121
+ */
122
+ function editFile(file, callback) {
123
+ const content = fs.readFileSync(file, "utf-8");
124
+ fs.writeFileSync(file, callback(content));
125
+ }
126
+ /**
127
+ * Copy template files to target directory with transformations
128
+ * @param templateDir - Source template directory
129
+ * @param root - Target root directory
130
+ * @param projectName - Project name for replacements
131
+ * @param packageName - Package name for package.json
132
+ * @throws Error if template copy fails or template directory doesn't exist
133
+ */
134
+ function copyTemplate(templateDir, root, projectName, packageName) {
135
+ if (!fs.existsSync(templateDir)) throw new Error(`Template directory not found: ${templateDir}`);
136
+ try {
137
+ if (!fs.existsSync(root)) fs.mkdirSync(root, { recursive: true });
138
+ const files = fs.readdirSync(templateDir);
139
+ for (const file of files) {
140
+ const srcFile = path.join(templateDir, file);
141
+ const stat = fs.statSync(srcFile);
142
+ if (stat.isDirectory()) {
143
+ const destDir = path.join(root, file);
144
+ copyDir(srcFile, destDir);
145
+ } else {
146
+ const destFileName = renameFiles[file] ?? file;
147
+ const destFile = path.join(root, destFileName);
148
+ fs.copyFileSync(srcFile, destFile);
149
+ }
150
+ }
151
+ const pkgJsonPath = path.join(root, "package.json");
152
+ if (fs.existsSync(pkgJsonPath)) editFile(pkgJsonPath, (content) => {
153
+ const pkg = JSON.parse(content);
154
+ pkg.name = packageName;
155
+ return JSON.stringify(pkg, null, 2) + "\n";
156
+ });
157
+ const indexHtmlPath = path.join(root, "index.html");
158
+ const playgroundIndexHtmlPath = path.join(root, "playground", "index.html");
159
+ if (fs.existsSync(indexHtmlPath)) editFile(indexHtmlPath, (content) => {
160
+ return content.replace(/<title>.*?<\/title>/, () => `<title>${projectName}</title>`);
161
+ });
162
+ if (fs.existsSync(playgroundIndexHtmlPath)) editFile(playgroundIndexHtmlPath, (content) => {
163
+ return content.replace(/<title>.*?<\/title>/, () => `<title>${projectName}</title>`);
164
+ });
165
+ } catch (error) {
166
+ if (error instanceof Error) throw new Error(`Failed to copy template: ${error.message}`);
167
+ throw error;
168
+ }
169
+ }
170
+
171
+ //#endregion
172
+ //#region src/utils/validation.ts
173
+ /**
174
+ * Validation utilities
175
+ */
176
+ /**
177
+ * Format target directory by removing trailing slashes and whitespace
178
+ * @param targetDir - The directory path to format
179
+ * @returns Formatted directory path
180
+ */
181
+ function formatTargetDir(targetDir) {
182
+ return targetDir?.trim().replace(/\/+$/g, "") ?? "";
183
+ }
184
+ /**
185
+ * Validate if a string is a valid npm package name
186
+ * @param projectName - The project name to validate
187
+ * @returns true if valid, false otherwise
188
+ */
189
+ function isValidPackageName(projectName) {
190
+ return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(projectName);
191
+ }
192
+ /**
193
+ * Convert a string to a valid npm package name
194
+ * @param projectName - The project name to convert
195
+ * @returns Valid npm package name
196
+ */
197
+ function toValidPackageName(projectName) {
198
+ const converted = projectName.trim().toLowerCase().replace(/\s+/g, "-").replace(/^[._]/, "").replace(/[^a-z0-9-~]+/g, "-");
199
+ return converted || "package";
200
+ }
201
+
202
+ //#endregion
203
+ //#region src/utils/package-manager.ts
204
+ /**
205
+ * Parse package manager information from user agent string
206
+ * @param userAgent - The user agent string (typically from npm_config_user_agent)
207
+ * @returns Package manager info or undefined if not found
208
+ */
209
+ function pkgFromUserAgent(userAgent) {
210
+ if (!userAgent) return void 0;
211
+ const pkgSpec = userAgent.split(" ")[0];
212
+ const pkgSpecArr = pkgSpec.split("/");
213
+ if (pkgSpecArr.length !== 2) return void 0;
214
+ return {
215
+ name: pkgSpecArr[0],
216
+ version: pkgSpecArr[1]
217
+ };
218
+ }
219
+ /**
220
+ * Get install command for a package manager
221
+ * @param agent - Package manager name (npm, pnpm, yarn, bun, deno)
222
+ * @returns Array of command parts
223
+ */
224
+ function getInstallCommand(agent) {
225
+ switch (agent) {
226
+ case "npm": return ["npm", "install"];
227
+ case "pnpm": return ["pnpm", "install"];
228
+ case "yarn": return ["yarn"];
229
+ case "bun": return ["bun", "install"];
230
+ case "deno": return ["deno", "install"];
231
+ default: return ["npm", "install"];
232
+ }
233
+ }
234
+ /**
235
+ * Get run command for a package manager
236
+ * @param agent - Package manager name (npm, pnpm, yarn, bun, deno)
237
+ * @param script - Script name to run
238
+ * @returns Array of command parts
239
+ */
240
+ function getRunCommand(agent, script) {
241
+ switch (agent) {
242
+ case "npm": return [
243
+ "npm",
244
+ "run",
245
+ script
246
+ ];
247
+ case "pnpm": return ["pnpm", script];
248
+ case "yarn": return ["yarn", script];
249
+ case "bun": return [
250
+ "bun",
251
+ "run",
252
+ script
253
+ ];
254
+ case "deno": return [
255
+ "deno",
256
+ "task",
257
+ script
258
+ ];
259
+ default: return [
260
+ "npm",
261
+ "run",
262
+ script
263
+ ];
264
+ }
265
+ }
266
+
267
+ //#endregion
268
+ //#region src/utils/prompts.ts
269
+ /**
270
+ * Exit the process (skipped in test mode)
271
+ * @param code - Exit code
272
+ */
273
+ function exitProcess$1(code) {
274
+ if (!process.env._ROLLDOWN_TEST_CLI) process.exit(code);
275
+ }
276
+ /**
277
+ * Prompt user for project name
278
+ * @param defaultValue - Default project name
279
+ * @returns Project name entered by user
280
+ */
281
+ async function promptProjectName(defaultValue) {
282
+ const result = await prompts.text({
283
+ message: "Project name:",
284
+ placeholder: defaultValue,
285
+ defaultValue,
286
+ validate: (value) => {
287
+ if (!value || value.trim().length === 0) return "Project name cannot be empty";
288
+ }
289
+ });
290
+ if (prompts.isCancel(result)) {
291
+ prompts.cancel("Operation cancelled");
292
+ exitProcess$1(0);
293
+ }
294
+ return result;
295
+ }
296
+ /**
297
+ * Prompt user for how to handle existing directory
298
+ * @param targetDir - The target directory path
299
+ * @returns User's choice: 'yes' (overwrite), 'no' (cancel), or 'ignore' (merge)
300
+ */
301
+ async function promptOverwrite(targetDir) {
302
+ const displayDir = targetDir === "." ? "Current directory" : `Target directory "${targetDir}"`;
303
+ const message = `${displayDir} is not empty. Please choose how to proceed:`;
304
+ const result = await prompts.select({
305
+ message,
306
+ options: [
307
+ {
308
+ value: "yes",
309
+ label: "Remove existing files and continue"
310
+ },
311
+ {
312
+ value: "no",
313
+ label: "Cancel operation"
314
+ },
315
+ {
316
+ value: "ignore",
317
+ label: "Ignore files and continue"
318
+ }
319
+ ]
320
+ });
321
+ if (prompts.isCancel(result)) {
322
+ prompts.cancel("Operation cancelled");
323
+ exitProcess$1(0);
324
+ }
325
+ return result;
326
+ }
327
+ /**
328
+ * Prompt user for package name
329
+ * @param defaultValue - Default package name
330
+ * @returns Valid package name entered by user
331
+ */
332
+ async function promptPackageName(defaultValue) {
333
+ const result = await prompts.text({
334
+ message: "Package name:",
335
+ placeholder: defaultValue,
336
+ defaultValue,
337
+ validate: (value) => {
338
+ if (!value || value.trim().length === 0) return "Package name cannot be empty";
339
+ if (!isValidPackageName(value)) return "Invalid package name (must follow npm naming conventions)";
340
+ }
341
+ });
342
+ if (prompts.isCancel(result)) {
343
+ prompts.cancel("Operation cancelled");
344
+ exitProcess$1(0);
345
+ }
346
+ return result;
347
+ }
348
+ /**
349
+ * Prompt user to select a framework
350
+ * @param frameworks - Array of available frameworks
351
+ * @returns Selected framework
352
+ */
353
+ async function promptFramework(frameworks) {
354
+ const result = await prompts.select({
355
+ message: "Select a framework:",
356
+ options: frameworks.map((framework) => ({
357
+ value: framework,
358
+ label: framework.color(framework.display)
359
+ }))
360
+ });
361
+ if (prompts.isCancel(result)) {
362
+ prompts.cancel("Operation cancelled");
363
+ exitProcess$1(0);
364
+ }
365
+ return result;
366
+ }
367
+ /**
368
+ * Prompt user to confirm immediate installation and start
369
+ * @param pkgManager - Package manager name
370
+ * @returns true if user wants to install and start immediately
371
+ */
372
+ async function promptImmediate(pkgManager) {
373
+ const result = await prompts.confirm({
374
+ message: `Install dependencies and start dev server with ${pkgManager}?`,
375
+ initialValue: false
376
+ });
377
+ if (prompts.isCancel(result)) {
378
+ prompts.cancel("Operation cancelled");
379
+ exitProcess$1(0);
380
+ }
381
+ return result;
382
+ }
383
+
384
+ //#endregion
385
+ //#region src/utils/command.ts
386
+ /**
387
+ * Execute a command using cross-spawn
388
+ * @param command - Command array [command, ...args]
389
+ * @param options - Spawn options
390
+ * @throws Error if command execution fails
391
+ */
392
+ function run(command, options) {
393
+ if (process.env._ROLLDOWN_TEST_CLI) return;
394
+ const [cmd, ...args] = command;
395
+ try {
396
+ const result = spawn.sync(cmd, args, {
397
+ stdio: "inherit",
398
+ ...options
399
+ });
400
+ if (result.error) throw new Error(`Failed to execute command: ${cmd} ${args.join(" ")}\n${result.error.message}`);
401
+ if (result.status !== 0) throw new Error(`Command failed with exit code ${result.status}: ${cmd} ${args.join(" ")}`);
402
+ } catch (error) {
403
+ if (error instanceof Error) console.error(pc.red(`\n✗ Command execution failed: ${error.message}`));
404
+ else console.error(pc.red(`\n✗ Command execution failed: ${String(error)}`));
405
+ throw error;
406
+ }
407
+ }
408
+ /**
409
+ * Install dependencies in the project directory
410
+ * @param root - Project root directory
411
+ * @param agent - Package manager name
412
+ * @throws Error if installation fails
413
+ */
414
+ function install(root, agent) {
415
+ const installCmd = getInstallCommand(agent);
416
+ console.log(pc.cyan(`\nInstalling dependencies with ${agent}...`));
417
+ if (process.env._ROLLDOWN_TEST_CLI) return;
418
+ try {
419
+ run(installCmd, { cwd: root });
420
+ } catch (error) {
421
+ console.error(pc.red(`\n✗ Failed to install dependencies with ${agent}`));
422
+ if (error instanceof Error) console.error(pc.red(`Error: ${error.message}`));
423
+ throw error;
424
+ }
425
+ }
426
+ /**
427
+ * Start the development server
428
+ * @param root - Project root directory
429
+ * @param agent - Package manager name
430
+ * @throws Error if server start fails
431
+ */
432
+ function start(root, agent) {
433
+ const runCmd = getRunCommand(agent, "dev");
434
+ console.log(pc.cyan(`\nStarting dev server...`));
435
+ if (process.env._ROLLDOWN_TEST_CLI) return;
436
+ try {
437
+ run(runCmd, { cwd: root });
438
+ } catch (error) {
439
+ console.error(pc.red(`\n✗ Failed to start dev server with ${agent}`));
440
+ if (error instanceof Error) console.error(pc.red(`Error: ${error.message}`));
441
+ throw error;
442
+ }
443
+ }
444
+
445
+ //#endregion
446
+ //#region src/utils/args.ts
447
+ /**
448
+ * Parse command line arguments
449
+ * @param argv - Command line arguments (defaults to process.argv.slice(2))
450
+ * @returns Parsed CLI arguments
451
+ */
452
+ function parseArguments(argv = process.argv.slice(2)) {
453
+ const args = mri(argv, {
454
+ alias: {
455
+ h: "help",
456
+ t: "template",
457
+ i: "immediate"
458
+ },
459
+ boolean: [
460
+ "help",
461
+ "overwrite",
462
+ "immediate",
463
+ "interactive"
464
+ ],
465
+ string: ["template"],
466
+ default: {
467
+ immediate: void 0,
468
+ interactive: void 0
469
+ }
470
+ });
471
+ return {
472
+ _: args._,
473
+ template: args.template,
474
+ help: args.help,
475
+ overwrite: args.overwrite,
476
+ immediate: args.immediate,
477
+ interactive: args.interactive
478
+ };
479
+ }
480
+ /**
481
+ * Display help information
482
+ */
483
+ function displayHelp() {
484
+ console.log(`
485
+ Usage: create-rolldown [project-name] [options]
486
+
487
+ Options:
488
+ -t, --template <name> Use a specific template
489
+ -h, --help Display this help message
490
+ --overwrite Overwrite existing files in target directory
491
+ -i, --immediate Install dependencies and start dev server immediately
492
+ --no-immediate Skip dependency installation
493
+ --interactive Force interactive mode
494
+ --no-interactive Force non-interactive mode
495
+
496
+ Available templates:
497
+ vanilla Vanilla TypeScript library (default)
498
+ react React library with TypeScript
499
+ vue Vue library with TypeScript
500
+ solid SolidJS library with TypeScript
501
+ svelte Svelte library with TypeScript
502
+
503
+ Examples:
504
+ $ npm create rolldown
505
+ $ npm create rolldown my-lib
506
+ $ npm create rolldown my-lib --template react
507
+ $ npm create rolldown my-lib -t vue --immediate
508
+ $ npm create rolldown my-lib --no-interactive --template solid
509
+ `);
510
+ }
511
+ /**
512
+ * Detect if CLI should run in interactive mode
513
+ * @param args - Parsed CLI arguments
514
+ * @returns true if interactive mode should be used
515
+ */
516
+ function shouldUseInteractiveMode(args) {
517
+ if (args.interactive !== void 0) return args.interactive;
518
+ const isTTY = process.stdout.isTTY && process.stdin.isTTY;
519
+ const isAIAgent = process.env.CI === "true" || process.env.CONTINUOUS_INTEGRATION === "true" || !isTTY;
520
+ return !isAIAgent;
521
+ }
522
+
523
+ //#endregion
524
+ //#region src/cli.ts
525
+ /**
526
+ * Exit the process (skipped in test mode)
527
+ * @param code - Exit code
528
+ */
529
+ function exitProcess(code) {
530
+ if (!process.env._ROLLDOWN_TEST_CLI) process.exit(code);
531
+ }
532
+ /**
533
+ * Main initialization function
534
+ * Orchestrates the entire project creation workflow
535
+ */
536
+ async function init() {
537
+ try {
538
+ const args = parseArguments();
539
+ if (args.help) {
540
+ displayHelp();
541
+ return;
542
+ }
543
+ const interactive = shouldUseInteractiveMode(args);
544
+ if (!interactive && !process.stdout.isTTY) {
545
+ console.log(pc.yellow("\nDetected non-interactive environment (AI agent or CI/CD)."));
546
+ console.log(pc.yellow("For best results, use: create-rolldown <project-name> --template <template> --no-interactive\n"));
547
+ }
548
+ const defaultProjectName = "rolldown-project";
549
+ let targetDir = formatTargetDir(args._[0]);
550
+ let projectName;
551
+ if (interactive && !targetDir) {
552
+ projectName = await promptProjectName(defaultProjectName);
553
+ targetDir = formatTargetDir(projectName);
554
+ } else {
555
+ projectName = targetDir || defaultProjectName;
556
+ targetDir = projectName;
557
+ }
558
+ const root = path.resolve(process.cwd(), targetDir);
559
+ if (fs.existsSync(root) && !isEmpty(root)) if (interactive) {
560
+ const overwrite = await promptOverwrite(targetDir);
561
+ if (overwrite === "no") {
562
+ console.log(pc.red("\nOperation cancelled"));
563
+ exitProcess(0);
564
+ } else if (overwrite === "yes") {
565
+ console.log(pc.cyan(`\nRemoving existing files in ${targetDir}...`));
566
+ try {
567
+ emptyDir(root);
568
+ } catch (error) {
569
+ console.error(pc.red(`\n✗ Failed to remove existing files`));
570
+ if (error instanceof Error) console.error(pc.red(`Error: ${error.message}`));
571
+ exitProcess(1);
572
+ }
573
+ }
574
+ } else if (args.overwrite) {
575
+ console.log(pc.cyan(`\nRemoving existing files in ${targetDir}...`));
576
+ try {
577
+ emptyDir(root);
578
+ } catch (error) {
579
+ console.error(pc.red(`\n✗ Failed to remove existing files`));
580
+ if (error instanceof Error) console.error(pc.red(`Error: ${error.message}`));
581
+ exitProcess(1);
582
+ }
583
+ } else {
584
+ console.log(pc.red(`\nTarget directory "${targetDir}" is not empty.`));
585
+ console.log(pc.red("Use --overwrite flag to overwrite existing files, or choose a different directory."));
586
+ exitProcess(1);
587
+ }
588
+ let packageName = toValidPackageName(projectName);
589
+ if (interactive && !isValidPackageName(projectName)) packageName = await promptPackageName(packageName);
590
+ let template = args.template;
591
+ if (interactive && !template) {
592
+ const framework = await promptFramework(FRAMEWORKS);
593
+ template = framework.name;
594
+ } else if (!template) template = "vanilla";
595
+ if (!TEMPLATES.includes(template)) if (interactive) {
596
+ console.log(pc.yellow(`\n"${template}" isn't a valid template. Please choose from below:\n`));
597
+ const framework = await promptFramework(FRAMEWORKS);
598
+ template = framework.name;
599
+ } else {
600
+ console.log(pc.yellow(`\nTemplate "${template}" not found. Using default template "vanilla".\n`));
601
+ template = "vanilla";
602
+ }
603
+ const pkgInfo = pkgFromUserAgent(process.env.npm_config_user_agent);
604
+ const pkgManager = pkgInfo?.name || "npm";
605
+ let shouldInstall = false;
606
+ if (args.immediate === true) shouldInstall = true;
607
+ else if (args.immediate === false) shouldInstall = false;
608
+ else if (interactive) shouldInstall = await promptImmediate(pkgManager);
609
+ console.log(pc.cyan(`\nScaffolding project in ${root}...`));
610
+ const templateDir = path.resolve(path.dirname(new URL(import.meta.url).pathname), "..", `template-${template}`);
611
+ try {
612
+ if (!fs.existsSync(root)) fs.mkdirSync(root, { recursive: true });
613
+ } catch (error) {
614
+ console.error(pc.red(`\n✗ Failed to create project directory`));
615
+ if (error instanceof Error) console.error(pc.red(`Error: ${error.message}`));
616
+ exitProcess(1);
617
+ }
618
+ try {
619
+ copyTemplate(templateDir, root, projectName, packageName);
620
+ } catch (error) {
621
+ console.error(pc.red(`\n✗ Failed to copy template files`));
622
+ if (error instanceof Error) console.error(pc.red(`Error: ${error.message}`));
623
+ exitProcess(1);
624
+ }
625
+ console.log(pc.green("\n✓ Project created successfully!"));
626
+ if (shouldInstall) try {
627
+ install(root, pkgManager);
628
+ console.log(pc.green("\n✓ Dependencies installed successfully!"));
629
+ start(root, pkgManager);
630
+ } catch (error) {
631
+ console.error(pc.red("\n✗ Failed to install dependencies or start server"));
632
+ if (error instanceof Error) console.error(pc.red(`Error: ${error.message}`));
633
+ exitProcess(1);
634
+ }
635
+ else {
636
+ console.log(pc.cyan("\nDone. Now run:\n"));
637
+ const cdCommand = path.relative(process.cwd(), root);
638
+ if (cdCommand) console.log(pc.cyan(` cd ${cdCommand}`));
639
+ const installCmd = getInstallCommand(pkgManager).join(" ");
640
+ console.log(pc.cyan(` ${installCmd}`));
641
+ const runCmd = getRunCommand(pkgManager, "dev").join(" ");
642
+ console.log(pc.cyan(` ${runCmd}`));
643
+ console.log();
644
+ }
645
+ } catch (error) {
646
+ if (error instanceof Error) console.error(pc.red(`\n✗ An unexpected error occurred: ${error.message}`));
647
+ else console.error(pc.red(`\n✗ An unexpected error occurred: ${String(error)}`));
648
+ exitProcess(1);
649
+ }
650
+ }
651
+ init().catch((error) => {
652
+ if (error instanceof Error && error.message !== "process.exit called with code 0") console.error(pc.red(`\n✗ Fatal error: ${error.message}`));
653
+ if (!process.env._ROLLDOWN_TEST_CLI && !process.env.VITEST) exitProcess(1);
654
+ });
655
+
656
+ //#endregion
657
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","names":["FRAMEWORKS: Framework[]","TEMPLATES: string[]","renameFiles: Record<string, string | undefined>","path: string","path","dir: string","src: string","dest: string","srcDir: string","destDir: string","file: string","callback: (content: string) => string","templateDir: string","root: string","projectName: string","packageName: string","targetDir: string | undefined","projectName: string","userAgent: string | undefined","agent: string","script: string","exitProcess","code: number","defaultValue: string","targetDir: string","frameworks: Framework[]","pkgManager: string","command: string[]","options?: SpawnOptions","root: string","agent: string","argv: string[]","args: CLIArguments","code: number","projectName: string"],"sources":["../src/utils/constants.ts","../src/utils/file.ts","../src/utils/validation.ts","../src/utils/package-manager.ts","../src/utils/prompts.ts","../src/utils/command.ts","../src/utils/args.ts","../src/cli.ts"],"sourcesContent":["/**\n * Constants for create-rolldown\n */\nimport pc from 'picocolors';\nimport type { Framework } from './types';\n\n/**\n * Supported frameworks with their variants\n * All templates use TypeScript and are designed for library development\n * (utility libraries, component libraries, tools, hooks, composables, etc.)\n */\nexport const FRAMEWORKS: Framework[] = [\n {\n name: 'vanilla',\n display: 'Vanilla',\n color: pc.yellow,\n },\n {\n name: 'react',\n display: 'React',\n color: pc.cyan,\n },\n {\n name: 'vue',\n display: 'Vue',\n color: pc.green,\n },\n {\n name: 'solid',\n display: 'Solid',\n color: pc.blue,\n },\n {\n name: 'svelte',\n display: 'Svelte',\n color: pc.red,\n },\n];\n\n/**\n * All available template names (flat list)\n */\nexport const TEMPLATES: string[] = FRAMEWORKS.map((f) => f.name);\n\n/**\n * File rename mappings for special files\n */\nexport const renameFiles: Record<string, string | undefined> = {\n _gitignore: '.gitignore',\n};\n","/**\n * File system utilities\n */\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { renameFiles } from './constants';\n\n/**\n * Check if a directory is empty (ignoring .git)\n * @param path - The directory path to check\n * @returns true if empty or only contains .git, false otherwise\n */\nexport function isEmpty(path: string): boolean {\n const files = fs.readdirSync(path);\n return files.length === 0 || (files.length === 1 && files[0] === '.git');\n}\n\n/**\n * Empty a directory but preserve .git folder\n * @param dir - The directory to empty\n * @throws Error if directory emptying fails\n */\nexport function emptyDir(dir: string): void {\n if (!fs.existsSync(dir)) {\n return;\n }\n try {\n for (const file of fs.readdirSync(dir)) {\n if (file === '.git') {\n continue;\n }\n fs.rmSync(path.resolve(dir, file), { recursive: true, force: true });\n }\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to empty directory ${dir}: ${error.message}`);\n }\n throw error;\n }\n}\n\n/**\n * Copy a file or directory\n * @param src - Source path\n * @param dest - Destination path\n * @throws Error if copy operation fails\n */\nexport function copy(src: string, dest: string): void {\n try {\n const stat = fs.statSync(src);\n if (stat.isDirectory()) {\n copyDir(src, dest);\n } else {\n fs.copyFileSync(src, dest);\n }\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to copy from ${src} to ${dest}: ${error.message}`);\n }\n throw error;\n }\n}\n\n/**\n * Recursively copy a directory\n * @param srcDir - Source directory\n * @param destDir - Destination directory\n * @throws Error if directory copy fails\n */\nexport function copyDir(srcDir: string, destDir: string): void {\n try {\n fs.mkdirSync(destDir, { recursive: true });\n for (const file of fs.readdirSync(srcDir)) {\n const srcFile = path.resolve(srcDir, file);\n const destFile = path.resolve(destDir, file);\n copy(srcFile, destFile);\n }\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to copy directory from ${srcDir} to ${destDir}: ${error.message}`);\n }\n throw error;\n }\n}\n\n/**\n * Write a file with optional content transformation\n * Handles special file renaming (e.g., _gitignore -> .gitignore)\n * @param file - File path to write\n * @param content - Optional content to write (if undefined, copies from template)\n */\nexport function write(file: string, content?: string): void {\n const targetPath = renameFiles[path.basename(file)] ?? file;\n if (content) {\n fs.writeFileSync(targetPath, content);\n } else {\n copy(file, targetPath);\n }\n}\n\n/**\n * Edit a file by applying a transformation function to its content\n * @param file - File path to edit\n * @param callback - Function that transforms the file content\n */\nexport function editFile(file: string, callback: (content: string) => string): void {\n const content = fs.readFileSync(file, 'utf-8');\n fs.writeFileSync(file, callback(content));\n}\n\n/**\n * Copy template files to target directory with transformations\n * @param templateDir - Source template directory\n * @param root - Target root directory\n * @param projectName - Project name for replacements\n * @param packageName - Package name for package.json\n * @throws Error if template copy fails or template directory doesn't exist\n */\nexport function copyTemplate(\n templateDir: string,\n root: string,\n projectName: string,\n packageName: string\n): void {\n // Validate template directory exists\n if (!fs.existsSync(templateDir)) {\n throw new Error(`Template directory not found: ${templateDir}`);\n }\n\n try {\n // Create target directory if it doesn't exist\n if (!fs.existsSync(root)) {\n fs.mkdirSync(root, { recursive: true });\n }\n\n const files = fs.readdirSync(templateDir);\n\n for (const file of files) {\n const srcFile = path.join(templateDir, file);\n const stat = fs.statSync(srcFile);\n\n if (stat.isDirectory()) {\n // Recursively copy directories\n const destDir = path.join(root, file);\n copyDir(srcFile, destDir);\n } else {\n // Handle file renaming for special files\n const destFileName = renameFiles[file] ?? file;\n const destFile = path.join(root, destFileName);\n\n // Copy the file\n fs.copyFileSync(srcFile, destFile);\n }\n }\n\n // Update package.json with the correct package name\n const pkgJsonPath = path.join(root, 'package.json');\n if (fs.existsSync(pkgJsonPath)) {\n editFile(pkgJsonPath, (content) => {\n const pkg = JSON.parse(content);\n pkg.name = packageName;\n return JSON.stringify(pkg, null, 2) + '\\n';\n });\n }\n\n // Update index.html with the correct project name (check both root and playground)\n const indexHtmlPath = path.join(root, 'index.html');\n const playgroundIndexHtmlPath = path.join(root, 'playground', 'index.html');\n\n if (fs.existsSync(indexHtmlPath)) {\n editFile(indexHtmlPath, (content) => {\n // Use a replacement function to avoid issues with special regex characters\n return content.replace(/<title>.*?<\\/title>/, () => `<title>${projectName}</title>`);\n });\n }\n\n if (fs.existsSync(playgroundIndexHtmlPath)) {\n editFile(playgroundIndexHtmlPath, (content) => {\n // Use a replacement function to avoid issues with special regex characters\n return content.replace(/<title>.*?<\\/title>/, () => `<title>${projectName}</title>`);\n });\n }\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to copy template: ${error.message}`);\n }\n throw error;\n }\n}\n","/**\n * Validation utilities\n */\n\n/**\n * Format target directory by removing trailing slashes and whitespace\n * @param targetDir - The directory path to format\n * @returns Formatted directory path\n */\nexport function formatTargetDir(targetDir: string | undefined): string {\n return targetDir?.trim().replace(/\\/+$/g, '') ?? '';\n}\n\n/**\n * Validate if a string is a valid npm package name\n * @param projectName - The project name to validate\n * @returns true if valid, false otherwise\n */\nexport function isValidPackageName(projectName: string): boolean {\n return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(projectName);\n}\n\n/**\n * Convert a string to a valid npm package name\n * @param projectName - The project name to convert\n * @returns Valid npm package name\n */\nexport function toValidPackageName(projectName: string): string {\n const converted = projectName\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/^[._]/, '')\n .replace(/[^a-z0-9-~]+/g, '-');\n\n // If the result is empty or invalid, return a default valid name\n return converted || 'package';\n}\n","/**\n * Package manager utilities\n */\nimport type { PkgInfo } from './types';\n\n/**\n * Parse package manager information from user agent string\n * @param userAgent - The user agent string (typically from npm_config_user_agent)\n * @returns Package manager info or undefined if not found\n */\nexport function pkgFromUserAgent(userAgent: string | undefined): PkgInfo | undefined {\n if (!userAgent) return undefined;\n\n const pkgSpec = userAgent.split(' ')[0];\n const pkgSpecArr = pkgSpec.split('/');\n\n if (pkgSpecArr.length !== 2) return undefined;\n\n return {\n name: pkgSpecArr[0],\n version: pkgSpecArr[1],\n };\n}\n\n/**\n * Get install command for a package manager\n * @param agent - Package manager name (npm, pnpm, yarn, bun, deno)\n * @returns Array of command parts\n */\nexport function getInstallCommand(agent: string): string[] {\n switch (agent) {\n case 'npm':\n return ['npm', 'install'];\n case 'pnpm':\n return ['pnpm', 'install'];\n case 'yarn':\n return ['yarn'];\n case 'bun':\n return ['bun', 'install'];\n case 'deno':\n return ['deno', 'install'];\n default:\n return ['npm', 'install'];\n }\n}\n\n/**\n * Get run command for a package manager\n * @param agent - Package manager name (npm, pnpm, yarn, bun, deno)\n * @param script - Script name to run\n * @returns Array of command parts\n */\nexport function getRunCommand(agent: string, script: string): string[] {\n switch (agent) {\n case 'npm':\n return ['npm', 'run', script];\n case 'pnpm':\n return ['pnpm', script];\n case 'yarn':\n return ['yarn', script];\n case 'bun':\n return ['bun', 'run', script];\n case 'deno':\n return ['deno', 'task', script];\n default:\n return ['npm', 'run', script];\n }\n}\n","/**\n * User prompt utilities\n */\nimport * as prompts from '@clack/prompts';\nimport type { Framework, FrameworkVariant } from './types';\nimport { isValidPackageName } from './validation';\n\n/**\n * Exit the process (skipped in test mode)\n * @param code - Exit code\n */\nfunction exitProcess(code: number): void {\n if (!process.env._ROLLDOWN_TEST_CLI) {\n process.exit(code);\n }\n}\n\n/**\n * Prompt user for project name\n * @param defaultValue - Default project name\n * @returns Project name entered by user\n */\nexport async function promptProjectName(defaultValue: string): Promise<string> {\n const result = await prompts.text({\n message: 'Project name:',\n placeholder: defaultValue,\n defaultValue,\n validate: (value) => {\n if (!value || value.trim().length === 0) {\n return 'Project name cannot be empty';\n }\n },\n });\n\n if (prompts.isCancel(result)) {\n prompts.cancel('Operation cancelled');\n exitProcess(0);\n }\n\n return result as string;\n}\n\n/**\n * Prompt user for how to handle existing directory\n * @param targetDir - The target directory path\n * @returns User's choice: 'yes' (overwrite), 'no' (cancel), or 'ignore' (merge)\n */\nexport async function promptOverwrite(targetDir: string): Promise<'yes' | 'no' | 'ignore'> {\n const displayDir = targetDir === '.' ? 'Current directory' : `Target directory \"${targetDir}\"`;\n const message = `${displayDir} is not empty. Please choose how to proceed:`;\n\n const result = await prompts.select({\n message,\n options: [\n {\n value: 'yes',\n label: 'Remove existing files and continue',\n },\n {\n value: 'no',\n label: 'Cancel operation',\n },\n {\n value: 'ignore',\n label: 'Ignore files and continue',\n },\n ],\n });\n\n if (prompts.isCancel(result)) {\n prompts.cancel('Operation cancelled');\n exitProcess(0);\n }\n\n return result as 'yes' | 'no' | 'ignore';\n}\n\n/**\n * Prompt user for package name\n * @param defaultValue - Default package name\n * @returns Valid package name entered by user\n */\nexport async function promptPackageName(defaultValue: string): Promise<string> {\n const result = await prompts.text({\n message: 'Package name:',\n placeholder: defaultValue,\n defaultValue,\n validate: (value) => {\n if (!value || value.trim().length === 0) {\n return 'Package name cannot be empty';\n }\n if (!isValidPackageName(value)) {\n return 'Invalid package name (must follow npm naming conventions)';\n }\n },\n });\n\n if (prompts.isCancel(result)) {\n prompts.cancel('Operation cancelled');\n exitProcess(0);\n }\n\n return result as string;\n}\n\n/**\n * Prompt user to select a framework\n * @param frameworks - Array of available frameworks\n * @returns Selected framework\n */\nexport async function promptFramework(frameworks: Framework[]): Promise<Framework> {\n const result = await prompts.select({\n message: 'Select a framework:',\n options: frameworks.map((framework) => ({\n value: framework,\n label: framework.color(framework.display),\n })),\n });\n\n if (prompts.isCancel(result)) {\n prompts.cancel('Operation cancelled');\n exitProcess(0);\n }\n\n return result as Framework;\n}\n\n/**\n * Prompt user to select a framework variant\n * @param variants - Array of available variants\n * @returns Selected variant name (template name)\n */\nexport async function promptVariant(variants: FrameworkVariant[]): Promise<string> {\n const result = await prompts.select({\n message: 'Select a variant:',\n options: variants.map((variant) => ({\n value: variant.name,\n label: variant.color(variant.display),\n })),\n });\n\n if (prompts.isCancel(result)) {\n prompts.cancel('Operation cancelled');\n exitProcess(0);\n }\n\n return result as string;\n}\n\n/**\n * Prompt user to confirm immediate installation and start\n * @param pkgManager - Package manager name\n * @returns true if user wants to install and start immediately\n */\nexport async function promptImmediate(pkgManager: string): Promise<boolean> {\n const result = await prompts.confirm({\n message: `Install dependencies and start dev server with ${pkgManager}?`,\n initialValue: false,\n });\n\n if (prompts.isCancel(result)) {\n prompts.cancel('Operation cancelled');\n exitProcess(0);\n }\n\n return result as boolean;\n}\n","/**\n * Command execution utilities\n */\nimport { SpawnOptions } from 'node:child_process';\nimport spawn from 'cross-spawn';\nimport pc from 'picocolors';\nimport { getInstallCommand, getRunCommand } from './package-manager';\n\n/**\n * Execute a command using cross-spawn\n * @param command - Command array [command, ...args]\n * @param options - Spawn options\n * @throws Error if command execution fails\n */\nexport function run(command: string[], options?: SpawnOptions): void {\n // Skip actual command execution in test environment\n if (process.env._ROLLDOWN_TEST_CLI) {\n return;\n }\n\n const [cmd, ...args] = command;\n\n try {\n const result = spawn.sync(cmd, args, {\n stdio: 'inherit',\n ...options,\n });\n\n if (result.error) {\n throw new Error(\n `Failed to execute command: ${cmd} ${args.join(' ')}\\n${result.error.message}`\n );\n }\n\n if (result.status !== 0) {\n throw new Error(`Command failed with exit code ${result.status}: ${cmd} ${args.join(' ')}`);\n }\n } catch (error) {\n if (error instanceof Error) {\n console.error(pc.red(`\\n✗ Command execution failed: ${error.message}`));\n } else {\n console.error(pc.red(`\\n✗ Command execution failed: ${String(error)}`));\n }\n throw error;\n }\n}\n\n/**\n * Install dependencies in the project directory\n * @param root - Project root directory\n * @param agent - Package manager name\n * @throws Error if installation fails\n */\nexport function install(root: string, agent: string): void {\n const installCmd = getInstallCommand(agent);\n console.log(pc.cyan(`\\nInstalling dependencies with ${agent}...`));\n\n // Skip actual installation in test environment\n if (process.env._ROLLDOWN_TEST_CLI) {\n return;\n }\n\n try {\n run(installCmd, { cwd: root });\n } catch (error) {\n console.error(pc.red(`\\n✗ Failed to install dependencies with ${agent}`));\n if (error instanceof Error) {\n console.error(pc.red(`Error: ${error.message}`));\n }\n throw error;\n }\n}\n\n/**\n * Start the development server\n * @param root - Project root directory\n * @param agent - Package manager name\n * @throws Error if server start fails\n */\nexport function start(root: string, agent: string): void {\n const runCmd = getRunCommand(agent, 'dev');\n console.log(pc.cyan(`\\nStarting dev server...`));\n\n // Skip actual server start in test environment\n if (process.env._ROLLDOWN_TEST_CLI) {\n return;\n }\n\n try {\n run(runCmd, { cwd: root });\n } catch (error) {\n console.error(pc.red(`\\n✗ Failed to start dev server with ${agent}`));\n if (error instanceof Error) {\n console.error(pc.red(`Error: ${error.message}`));\n }\n throw error;\n }\n}\n","/**\n * Command line argument parsing utilities\n */\nimport mri from 'mri';\nimport type { CLIArguments } from './types';\n\n/**\n * Parse command line arguments\n * @param argv - Command line arguments (defaults to process.argv.slice(2))\n * @returns Parsed CLI arguments\n */\nexport function parseArguments(argv: string[] = process.argv.slice(2)): CLIArguments {\n const args = mri(argv, {\n alias: {\n h: 'help',\n t: 'template',\n i: 'immediate',\n },\n boolean: ['help', 'overwrite', 'immediate', 'interactive'],\n string: ['template'],\n default: {\n immediate: undefined,\n interactive: undefined,\n },\n });\n\n return {\n _: args._,\n template: args.template,\n help: args.help,\n overwrite: args.overwrite,\n immediate: args.immediate,\n interactive: args.interactive,\n };\n}\n\n/**\n * Display help information\n */\nexport function displayHelp(): void {\n console.log(`\nUsage: create-rolldown [project-name] [options]\n\nOptions:\n -t, --template <name> Use a specific template\n -h, --help Display this help message\n --overwrite Overwrite existing files in target directory\n -i, --immediate Install dependencies and start dev server immediately\n --no-immediate Skip dependency installation\n --interactive Force interactive mode\n --no-interactive Force non-interactive mode\n\nAvailable templates:\n vanilla Vanilla TypeScript library (default)\n react React library with TypeScript\n vue Vue library with TypeScript\n solid SolidJS library with TypeScript\n svelte Svelte library with TypeScript\n\nExamples:\n $ npm create rolldown\n $ npm create rolldown my-lib\n $ npm create rolldown my-lib --template react\n $ npm create rolldown my-lib -t vue --immediate\n $ npm create rolldown my-lib --no-interactive --template solid\n`);\n}\n\n/**\n * Detect if CLI should run in interactive mode\n * @param args - Parsed CLI arguments\n * @returns true if interactive mode should be used\n */\nexport function shouldUseInteractiveMode(args: CLIArguments): boolean {\n // If explicitly set via --interactive or --no-interactive, use that\n if (args.interactive !== undefined) {\n return args.interactive;\n }\n\n // Check if running in a TTY environment\n const isTTY = process.stdout.isTTY && process.stdin.isTTY;\n\n // Check for AI agent environment (common CI/CD or agent indicators)\n const isAIAgent =\n process.env.CI === 'true' || process.env.CONTINUOUS_INTEGRATION === 'true' || !isTTY;\n\n return !isAIAgent;\n}\n","#!/usr/bin/env node\n\n/**\n * create-rolldown - Scaffolding tool for Rolldown projects\n * CLI entry point\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport pc from 'picocolors';\nimport {\n parseArguments,\n displayHelp,\n shouldUseInteractiveMode,\n formatTargetDir,\n isEmpty,\n emptyDir,\n toValidPackageName,\n isValidPackageName,\n copyTemplate,\n pkgFromUserAgent,\n getInstallCommand,\n getRunCommand,\n install,\n start,\n promptProjectName,\n promptOverwrite,\n promptPackageName,\n promptFramework,\n promptImmediate,\n FRAMEWORKS,\n TEMPLATES,\n} from './utils';\n\n/**\n * Exit the process (skipped in test mode)\n * @param code - Exit code\n */\nfunction exitProcess(code: number): void {\n if (!process.env._ROLLDOWN_TEST_CLI) {\n process.exit(code);\n }\n}\n\n/**\n * Main initialization function\n * Orchestrates the entire project creation workflow\n */\nasync function init(): Promise<void> {\n try {\n const args = parseArguments();\n\n // Display help if requested\n if (args.help) {\n displayHelp();\n return;\n }\n\n // Detect interactive mode\n const interactive = shouldUseInteractiveMode(args);\n\n // Detect AI agent environment and provide guidance\n if (!interactive && !process.stdout.isTTY) {\n console.log(pc.yellow('\\nDetected non-interactive environment (AI agent or CI/CD).'));\n console.log(\n pc.yellow(\n 'For best results, use: create-rolldown <project-name> --template <template> --no-interactive\\n'\n )\n );\n }\n\n // Get target directory from arguments or use default\n const defaultProjectName = 'rolldown-project';\n let targetDir = formatTargetDir(args._[0]);\n\n // Get project name (interactive or from args)\n let projectName: string;\n if (interactive && !targetDir) {\n projectName = await promptProjectName(defaultProjectName);\n targetDir = formatTargetDir(projectName);\n } else {\n projectName = targetDir || defaultProjectName;\n targetDir = projectName;\n }\n\n // Resolve to absolute path\n const root = path.resolve(process.cwd(), targetDir);\n\n // Handle directory conflicts\n if (fs.existsSync(root) && !isEmpty(root)) {\n if (interactive) {\n const overwrite = await promptOverwrite(targetDir);\n\n if (overwrite === 'no') {\n console.log(pc.red('\\nOperation cancelled'));\n exitProcess(0);\n } else if (overwrite === 'yes') {\n console.log(pc.cyan(`\\nRemoving existing files in ${targetDir}...`));\n try {\n emptyDir(root);\n } catch (error) {\n console.error(pc.red(`\\n✗ Failed to remove existing files`));\n if (error instanceof Error) {\n console.error(pc.red(`Error: ${error.message}`));\n }\n exitProcess(1);\n }\n }\n // If 'ignore', continue without clearing\n } else {\n // Non-interactive mode\n if (args.overwrite) {\n console.log(pc.cyan(`\\nRemoving existing files in ${targetDir}...`));\n try {\n emptyDir(root);\n } catch (error) {\n console.error(pc.red(`\\n✗ Failed to remove existing files`));\n if (error instanceof Error) {\n console.error(pc.red(`Error: ${error.message}`));\n }\n exitProcess(1);\n }\n } else {\n console.log(pc.red(`\\nTarget directory \"${targetDir}\" is not empty.`));\n console.log(\n pc.red(\n 'Use --overwrite flag to overwrite existing files, or choose a different directory.'\n )\n );\n exitProcess(1);\n }\n }\n }\n\n // Get package name\n let packageName = toValidPackageName(projectName);\n if (interactive && !isValidPackageName(projectName)) {\n packageName = await promptPackageName(packageName);\n }\n\n // Get template\n let template = args.template;\n\n if (interactive && !template) {\n // Prompt for framework (directly get template name)\n const framework = await promptFramework(FRAMEWORKS);\n template = framework.name; // Use framework name directly as template\n } else if (!template) {\n // Non-interactive mode without template - use default\n template = 'vanilla';\n }\n\n // Validate template\n if (!TEMPLATES.includes(template)) {\n if (interactive) {\n console.log(\n pc.yellow(`\\n\"${template}\" isn't a valid template. Please choose from below:\\n`)\n );\n const framework = await promptFramework(FRAMEWORKS);\n template = framework.name; // Use framework name directly as template\n } else {\n console.log(\n pc.yellow(`\\nTemplate \"${template}\" not found. Using default template \"vanilla\".\\n`)\n );\n template = 'vanilla';\n }\n }\n\n // Detect package manager\n const pkgInfo = pkgFromUserAgent(process.env.npm_config_user_agent);\n const pkgManager = pkgInfo?.name || 'npm';\n\n // Ask about immediate installation (interactive only)\n let shouldInstall = false;\n if (args.immediate === true) {\n shouldInstall = true;\n } else if (args.immediate === false) {\n shouldInstall = false;\n } else if (interactive) {\n shouldInstall = await promptImmediate(pkgManager);\n }\n\n // Start scaffolding\n console.log(pc.cyan(`\\nScaffolding project in ${root}...`));\n\n // Get template directory\n const templateDir = path.resolve(\n path.dirname(new URL(import.meta.url).pathname),\n '..',\n `template-${template}`\n );\n\n // Create target directory if it doesn't exist\n try {\n if (!fs.existsSync(root)) {\n fs.mkdirSync(root, { recursive: true });\n }\n } catch (error) {\n console.error(pc.red(`\\n✗ Failed to create project directory`));\n if (error instanceof Error) {\n console.error(pc.red(`Error: ${error.message}`));\n }\n exitProcess(1);\n }\n\n // Copy template files\n try {\n copyTemplate(templateDir, root, projectName, packageName);\n } catch (error) {\n console.error(pc.red(`\\n✗ Failed to copy template files`));\n if (error instanceof Error) {\n console.error(pc.red(`Error: ${error.message}`));\n }\n exitProcess(1);\n }\n\n console.log(pc.green('\\n✓ Project created successfully!'));\n\n // Install dependencies and start server if requested\n if (shouldInstall) {\n try {\n install(root, pkgManager);\n console.log(pc.green('\\n✓ Dependencies installed successfully!'));\n\n start(root, pkgManager);\n } catch (error) {\n console.error(pc.red('\\n✗ Failed to install dependencies or start server'));\n if (error instanceof Error) {\n console.error(pc.red(`Error: ${error.message}`));\n }\n exitProcess(1);\n }\n } else {\n // Display next steps\n console.log(pc.cyan('\\nDone. Now run:\\n'));\n\n const cdCommand = path.relative(process.cwd(), root);\n if (cdCommand) {\n console.log(pc.cyan(` cd ${cdCommand}`));\n }\n\n const installCmd = getInstallCommand(pkgManager).join(' ');\n console.log(pc.cyan(` ${installCmd}`));\n\n const runCmd = getRunCommand(pkgManager, 'dev').join(' ');\n console.log(pc.cyan(` ${runCmd}`));\n\n console.log();\n }\n } catch (error) {\n // Handle any unexpected errors\n if (error instanceof Error) {\n console.error(pc.red(`\\n✗ An unexpected error occurred: ${error.message}`));\n } else {\n console.error(pc.red(`\\n✗ An unexpected error occurred: ${String(error)}`));\n }\n exitProcess(1);\n }\n}\n\n// Run init function\ninit().catch((error) => {\n // Error handling is already done in init(), but catch any unhandled errors\n if (error instanceof Error && error.message !== 'process.exit called with code 0') {\n console.error(pc.red(`\\n✗ Fatal error: ${error.message}`));\n }\n if (!process.env._ROLLDOWN_TEST_CLI && !process.env.VITEST) {\n exitProcess(1);\n }\n});\n"],"mappings":"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"}
package/index.js ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+
3
+ // Entry point that imports the compiled TypeScript code
4
+ import './dist/cli.js';
package/package.json CHANGED
@@ -1,63 +1,72 @@
1
1
  {
2
2
  "name": "create-rolldown",
3
- "type": "module",
4
- "version": "0.0.0",
5
- "packageManager": "pnpm@10.6.2",
6
- "description": "_description_",
7
- "author": "Sunny-117",
3
+ "version": "0.0.2",
4
+ "description": "Scaffolding tool for Rolldown projects",
5
+ "keywords": [
6
+ "bundler",
7
+ "cli",
8
+ "create-app",
9
+ "rolldown",
10
+ "scaffolding",
11
+ "template"
12
+ ],
13
+ "homepage": "https://github.com/sunny-117/create-rolldown",
14
+ "bugs": {
15
+ "url": "https://github.com/sunny-117/create-rolldown/issues"
16
+ },
8
17
  "license": "MIT",
9
- "funding": "https://github.com/sponsors/Sunny-117",
10
- "homepage": "https://github.com/Sunny-117/create-rolldown#readme",
18
+ "author": "Sunny-117",
11
19
  "repository": {
12
20
  "type": "git",
13
- "url": "git+https://github.com/Sunny-117/create-rolldown.git"
21
+ "url": "https://github.com/sunny-117/create-rolldown.git"
14
22
  },
15
- "bugs": "https://github.com/Sunny-117/create-rolldown/issues",
16
- "keywords": [],
17
- "sideEffects": false,
18
- "exports": {
19
- ".": "./dist/index.mjs",
20
- "./package.json": "./package.json"
23
+ "bin": {
24
+ "create-rolldown": "index.js"
21
25
  },
22
- "main": "./dist/index.mjs",
23
- "module": "./dist/index.mjs",
24
- "types": "./dist/index.d.mts",
25
26
  "files": [
27
+ "index.js",
28
+ "template-*",
26
29
  "dist"
27
30
  ],
31
+ "type": "module",
28
32
  "scripts": {
29
- "build": "unbuild",
30
- "dev": "unbuild --stub",
31
- "lint": "eslint",
32
- "prepublishOnly": "nr build",
33
- "release": "bumpp && pnpm publish",
34
- "start": "tsx src/index.ts",
35
- "test": "vitest",
33
+ "dev": "tsdown --watch",
34
+ "build": "tsdown",
36
35
  "typecheck": "tsc --noEmit",
37
- "prepare": "simple-git-hooks"
36
+ "test": "vitest --run",
37
+ "test:watch": "vitest",
38
+ "lint": "oxlint",
39
+ "format": "oxfmt",
40
+ "format:check": "oxfmt --check",
41
+ "prepare": "simple-git-hooks",
42
+ "prepublishOnly": "pnpm build && pnpm test",
43
+ "release": "pnpm test && changelogen --release --bump prerelease && npm publish && git push --follow-tags"
44
+ },
45
+ "dependencies": {
46
+ "@clack/prompts": "^0.7.0",
47
+ "@vercel/detect-agent": "^1.0.0",
48
+ "cross-spawn": "^7.0.3",
49
+ "mri": "^1.2.0",
50
+ "picocolors": "^1.0.0"
38
51
  },
39
52
  "devDependencies": {
40
- "@antfu/eslint-config": "^4.12.0",
41
- "@antfu/ni": "^24.3.0",
42
- "@antfu/utils": "^9.2.0",
43
- "@types/node": "^22.14.1",
44
- "bumpp": "^10.1.0",
45
- "eslint": "^9.25.1",
46
- "lint-staged": "^15.5.1",
53
+ "@types/cross-spawn": "^6.0.6",
54
+ "@types/mri": "^1.1.5",
55
+ "@types/node": "^20.11.0",
56
+ "changelogen": "^0.6.2",
57
+ "execa": "^9.0.0",
58
+ "fast-check": "^3.15.0",
59
+ "oxfmt": "^0.24.0",
60
+ "oxlint": "^0.17.0",
47
61
  "simple-git-hooks": "^2.12.1",
48
- "tinyexec": "^1.0.1",
49
- "tsx": "^4.19.3",
50
- "typescript": "^5.8.3",
51
- "unbuild": "^3.5.0",
52
- "vite": "^6.3.2",
53
- "vitest": "^3.1.2",
54
- "vitest-package-exports": "^0.1.1",
55
- "yaml": "^2.7.1"
62
+ "tsdown": "^0.2.0",
63
+ "typescript": "^5.3.3",
64
+ "vitest": "^1.2.0"
56
65
  },
57
66
  "simple-git-hooks": {
58
- "pre-commit": "pnpm i --frozen-lockfile --ignore-scripts --offline && npx lint-staged"
67
+ "pre-commit": "pnpm format && pnpm lint"
59
68
  },
60
- "lint-staged": {
61
- "*": "eslint --fix"
69
+ "engines": {
70
+ "node": "^20.19.0 || >=22.12.0"
62
71
  }
63
72
  }
package/dist/index.d.mts DELETED
@@ -1,4 +0,0 @@
1
- declare const one = 1;
2
- declare const two = 2;
3
-
4
- export { one, two };
package/dist/index.mjs DELETED
@@ -1,4 +0,0 @@
1
- const one = 1;
2
- const two = 2;
3
-
4
- export { one, two };