create-bunli 0.1.0
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 +302 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +310 -0
- package/dist/create-project.d.ts +13 -0
- package/dist/create.d.ts +13 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +217 -0
- package/dist/template-engine.d.ts +27 -0
- package/dist/templates/advanced/README.md +114 -0
- package/dist/templates/advanced/package.json +36 -0
- package/dist/templates/advanced/src/commands/config.ts +145 -0
- package/dist/templates/advanced/src/commands/init.ts +153 -0
- package/dist/templates/advanced/src/commands/serve.ts +176 -0
- package/dist/templates/advanced/src/commands/validate.ts +116 -0
- package/dist/templates/advanced/src/index.ts +44 -0
- package/dist/templates/advanced/src/utils/config.ts +83 -0
- package/dist/templates/advanced/src/utils/constants.ts +12 -0
- package/dist/templates/advanced/src/utils/glob.ts +49 -0
- package/dist/templates/advanced/src/utils/validator.ts +131 -0
- package/dist/templates/advanced/template.json +37 -0
- package/dist/templates/advanced/test/commands.test.ts +34 -0
- package/dist/templates/advanced/tsconfig.json +23 -0
- package/dist/templates/basic/README.md +41 -0
- package/dist/templates/basic/package.json +29 -0
- package/dist/templates/basic/src/commands/hello.ts +29 -0
- package/dist/templates/basic/src/index.ts +13 -0
- package/dist/templates/basic/template.json +31 -0
- package/dist/templates/basic/test/hello.test.ts +26 -0
- package/dist/templates/basic/tsconfig.json +19 -0
- package/dist/templates/monorepo/README.md +74 -0
- package/dist/templates/monorepo/package.json +28 -0
- package/dist/templates/monorepo/packages/cli/package.json +34 -0
- package/dist/templates/monorepo/packages/cli/src/index.ts +22 -0
- package/dist/templates/monorepo/packages/cli/tsconfig.json +15 -0
- package/dist/templates/monorepo/packages/core/package.json +32 -0
- package/dist/templates/monorepo/packages/core/scripts/build.ts +18 -0
- package/dist/templates/monorepo/packages/core/src/commands/analyze.ts +84 -0
- package/dist/templates/monorepo/packages/core/src/commands/process.ts +64 -0
- package/dist/templates/monorepo/packages/core/src/index.ts +3 -0
- package/dist/templates/monorepo/packages/core/src/types.ts +21 -0
- package/dist/templates/monorepo/packages/core/tsconfig.json +15 -0
- package/dist/templates/monorepo/packages/utils/package.json +26 -0
- package/dist/templates/monorepo/packages/utils/scripts/build.ts +17 -0
- package/dist/templates/monorepo/packages/utils/src/format.ts +27 -0
- package/dist/templates/monorepo/packages/utils/src/index.ts +3 -0
- package/dist/templates/monorepo/packages/utils/src/json.ts +11 -0
- package/dist/templates/monorepo/packages/utils/src/logger.ts +19 -0
- package/dist/templates/monorepo/packages/utils/tsconfig.json +12 -0
- package/dist/templates/monorepo/template.json +24 -0
- package/dist/templates/monorepo/tsconfig.json +14 -0
- package/dist/templates/monorepo/turbo.json +28 -0
- package/dist/types.d.ts +48 -0
- package/package.json +57 -0
- package/templates/advanced/README.md +114 -0
- package/templates/advanced/package.json +36 -0
- package/templates/advanced/src/commands/config.ts +145 -0
- package/templates/advanced/src/commands/init.ts +153 -0
- package/templates/advanced/src/commands/serve.ts +176 -0
- package/templates/advanced/src/commands/validate.ts +116 -0
- package/templates/advanced/src/index.ts +44 -0
- package/templates/advanced/src/utils/config.ts +83 -0
- package/templates/advanced/src/utils/constants.ts +12 -0
- package/templates/advanced/src/utils/glob.ts +49 -0
- package/templates/advanced/src/utils/validator.ts +131 -0
- package/templates/advanced/template.json +37 -0
- package/templates/advanced/test/commands.test.ts +34 -0
- package/templates/advanced/tsconfig.json +23 -0
- package/templates/basic/README.md +41 -0
- package/templates/basic/package.json +29 -0
- package/templates/basic/src/commands/hello.ts +29 -0
- package/templates/basic/src/index.ts +13 -0
- package/templates/basic/template.json +31 -0
- package/templates/basic/test/hello.test.ts +26 -0
- package/templates/basic/tsconfig.json +19 -0
- package/templates/monorepo/README.md +74 -0
- package/templates/monorepo/package.json +28 -0
- package/templates/monorepo/packages/cli/package.json +34 -0
- package/templates/monorepo/packages/cli/src/index.ts +22 -0
- package/templates/monorepo/packages/cli/tsconfig.json +15 -0
- package/templates/monorepo/packages/core/package.json +32 -0
- package/templates/monorepo/packages/core/scripts/build.ts +18 -0
- package/templates/monorepo/packages/core/src/commands/analyze.ts +84 -0
- package/templates/monorepo/packages/core/src/commands/process.ts +64 -0
- package/templates/monorepo/packages/core/src/index.ts +3 -0
- package/templates/monorepo/packages/core/src/types.ts +21 -0
- package/templates/monorepo/packages/core/tsconfig.json +15 -0
- package/templates/monorepo/packages/utils/package.json +26 -0
- package/templates/monorepo/packages/utils/scripts/build.ts +17 -0
- package/templates/monorepo/packages/utils/src/format.ts +27 -0
- package/templates/monorepo/packages/utils/src/index.ts +3 -0
- package/templates/monorepo/packages/utils/src/json.ts +11 -0
- package/templates/monorepo/packages/utils/src/logger.ts +19 -0
- package/templates/monorepo/packages/utils/tsconfig.json +12 -0
- package/templates/monorepo/template.json +24 -0
- package/templates/monorepo/tsconfig.json +14 -0
- package/templates/monorepo/turbo.json +28 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { $ } from 'bun'
|
|
3
|
+
|
|
4
|
+
// Clean dist directory
|
|
5
|
+
await $`rm -rf dist`
|
|
6
|
+
await $`mkdir -p dist`
|
|
7
|
+
|
|
8
|
+
// Build TypeScript files
|
|
9
|
+
await Bun.build({
|
|
10
|
+
entrypoints: ['./src/index.ts'],
|
|
11
|
+
outdir: './dist',
|
|
12
|
+
target: 'bun',
|
|
13
|
+
format: 'esm',
|
|
14
|
+
minify: false
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
console.log('✅ @{{projectName}}/utils built successfully')
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export function formatTable(data: Record<string, any>[]): string {
|
|
2
|
+
if (data.length === 0) return ''
|
|
3
|
+
|
|
4
|
+
const headers = Object.keys(data[0])
|
|
5
|
+
const rows = data.map(item => headers.map(h => String(item[h] ?? '')))
|
|
6
|
+
|
|
7
|
+
// Calculate column widths
|
|
8
|
+
const widths = headers.map((h, i) => {
|
|
9
|
+
const headerWidth = h.length
|
|
10
|
+
const maxDataWidth = Math.max(...rows.map(r => r[i].length))
|
|
11
|
+
return Math.max(headerWidth, maxDataWidth)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
// Build table
|
|
15
|
+
const lines: string[] = []
|
|
16
|
+
|
|
17
|
+
// Header
|
|
18
|
+
lines.push(headers.map((h, i) => h.padEnd(widths[i])).join(' '))
|
|
19
|
+
lines.push(widths.map(w => '-'.repeat(w)).join(' '))
|
|
20
|
+
|
|
21
|
+
// Rows
|
|
22
|
+
for (const row of rows) {
|
|
23
|
+
lines.push(row.map((cell, i) => cell.padEnd(widths[i])).join(' '))
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return lines.join('\\n')
|
|
27
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function parseJSON<T = any>(text: string): T {
|
|
2
|
+
try {
|
|
3
|
+
return JSON.parse(text)
|
|
4
|
+
} catch (error) {
|
|
5
|
+
throw new Error(`Invalid JSON: ${error}`)
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function stringifyJSON(data: any, pretty = false): string {
|
|
10
|
+
return JSON.stringify(data, null, pretty ? 2 : 0)
|
|
11
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const logger = {
|
|
2
|
+
debug: (...args: any[]) => {
|
|
3
|
+
if (process.env.DEBUG) {
|
|
4
|
+
console.log('[DEBUG]', ...args)
|
|
5
|
+
}
|
|
6
|
+
},
|
|
7
|
+
|
|
8
|
+
info: (...args: any[]) => {
|
|
9
|
+
console.log('[INFO]', ...args)
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
warn: (...args: any[]) => {
|
|
13
|
+
console.warn('[WARN]', ...args)
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
error: (...args: any[]) => {
|
|
17
|
+
console.error('[ERROR]', ...args)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "./dist",
|
|
5
|
+
"rootDir": "./src",
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"declarationMap": true,
|
|
8
|
+
"composite": true
|
|
9
|
+
},
|
|
10
|
+
"include": ["src/**/*"],
|
|
11
|
+
"exclude": ["node_modules", "dist", "test/**/*"]
|
|
12
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "bunli-monorepo",
|
|
3
|
+
"description": "Monorepo template for multi-package Bunli projects",
|
|
4
|
+
"variables": [
|
|
5
|
+
{
|
|
6
|
+
"name": "projectName",
|
|
7
|
+
"message": "Project name",
|
|
8
|
+
"type": "string",
|
|
9
|
+
"default": "my-bunli-monorepo"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"name": "description",
|
|
13
|
+
"message": "Project description",
|
|
14
|
+
"type": "string",
|
|
15
|
+
"default": "A monorepo CLI project built with Bunli"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "author",
|
|
19
|
+
"message": "Author name",
|
|
20
|
+
"type": "string",
|
|
21
|
+
"default": ""
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"forceConsistentCasingInFileNames": true,
|
|
10
|
+
"resolveJsonModule": true,
|
|
11
|
+
"types": ["bun-types"]
|
|
12
|
+
},
|
|
13
|
+
"exclude": ["node_modules", "dist", "build", ".turbo"]
|
|
14
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://turbo.build/schema.json",
|
|
3
|
+
"globalDependencies": ["**/.env.*local"],
|
|
4
|
+
"pipeline": {
|
|
5
|
+
"build": {
|
|
6
|
+
"dependsOn": ["^build"],
|
|
7
|
+
"outputs": ["dist/**", ".next/**", "!.next/cache/**"]
|
|
8
|
+
},
|
|
9
|
+
"test": {
|
|
10
|
+
"dependsOn": ["build"],
|
|
11
|
+
"outputs": ["coverage/**"],
|
|
12
|
+
"cache": false
|
|
13
|
+
},
|
|
14
|
+
"lint": {
|
|
15
|
+
"dependsOn": ["^build"]
|
|
16
|
+
},
|
|
17
|
+
"type-check": {
|
|
18
|
+
"dependsOn": ["^build"]
|
|
19
|
+
},
|
|
20
|
+
"dev": {
|
|
21
|
+
"cache": false,
|
|
22
|
+
"persistent": true
|
|
23
|
+
},
|
|
24
|
+
"clean": {
|
|
25
|
+
"cache": false
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export interface CreateOptions {
|
|
2
|
+
template?: string;
|
|
3
|
+
packageManager?: PackageManager;
|
|
4
|
+
install?: boolean;
|
|
5
|
+
git?: boolean;
|
|
6
|
+
offline?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export type PackageManager = 'bun' | 'npm' | 'yarn' | 'pnpm';
|
|
9
|
+
export interface ProjectConfig {
|
|
10
|
+
name: string;
|
|
11
|
+
template: string;
|
|
12
|
+
packageManager: PackageManager;
|
|
13
|
+
install: boolean;
|
|
14
|
+
git: boolean;
|
|
15
|
+
offline?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface TemplateManifest {
|
|
18
|
+
name?: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
variables?: TemplateVariable[];
|
|
21
|
+
files?: {
|
|
22
|
+
include?: string[];
|
|
23
|
+
exclude?: string[];
|
|
24
|
+
};
|
|
25
|
+
hooks?: {
|
|
26
|
+
postInstall?: string[];
|
|
27
|
+
};
|
|
28
|
+
requirements?: {
|
|
29
|
+
node?: string;
|
|
30
|
+
bun?: string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export interface TemplateVariable {
|
|
34
|
+
name: string;
|
|
35
|
+
message: string;
|
|
36
|
+
type?: 'string' | 'boolean' | 'number' | 'select';
|
|
37
|
+
default?: any;
|
|
38
|
+
choices?: Array<{
|
|
39
|
+
label: string;
|
|
40
|
+
value: any;
|
|
41
|
+
}>;
|
|
42
|
+
validate?: (value: any) => boolean | string;
|
|
43
|
+
}
|
|
44
|
+
export interface Template {
|
|
45
|
+
name: string;
|
|
46
|
+
description: string;
|
|
47
|
+
files: Record<string, string>;
|
|
48
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-bunli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Scaffold new Bunli CLI projects",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-bunli": "./dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"module": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"templates"
|
|
20
|
+
],
|
|
21
|
+
"author": "Arya Labs, Inc.",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/AryaLabsHQ/bunli.git",
|
|
26
|
+
"directory": "packages/create-bunli"
|
|
27
|
+
},
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/AryaLabsHQ/bunli/issues"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://github.com/AryaLabsHQ/bunli#readme",
|
|
32
|
+
"keywords": [
|
|
33
|
+
"bunli",
|
|
34
|
+
"create",
|
|
35
|
+
"scaffold",
|
|
36
|
+
"cli",
|
|
37
|
+
"starter",
|
|
38
|
+
"template",
|
|
39
|
+
"bun",
|
|
40
|
+
"typescript"
|
|
41
|
+
],
|
|
42
|
+
"scripts": {
|
|
43
|
+
"dev": "bun run src/cli.ts",
|
|
44
|
+
"build": "bun scripts/build.ts && bun run tsc",
|
|
45
|
+
"test": "bun test",
|
|
46
|
+
"type-check": "tsc --noEmit"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@bunli/core": "0.1.0",
|
|
50
|
+
"@bunli/utils": "0.1.0",
|
|
51
|
+
"giget": "^2.0.0"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@types/bun": "latest",
|
|
55
|
+
"typescript": "^5.8.0"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# {{projectName}}
|
|
2
|
+
|
|
3
|
+
{{description}}
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Install globally
|
|
9
|
+
bun add -g {{projectName}}
|
|
10
|
+
|
|
11
|
+
# Or use directly with bunx
|
|
12
|
+
bunx {{projectName}} [command]
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
{{projectName}} <command> [options]
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Commands
|
|
22
|
+
|
|
23
|
+
#### `init`
|
|
24
|
+
Initialize a new configuration file in the current directory.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
{{projectName}} init [options]
|
|
28
|
+
|
|
29
|
+
Options:
|
|
30
|
+
-f, --force Overwrite existing config
|
|
31
|
+
-t, --template Config template to use
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
#### `validate`
|
|
35
|
+
Validate files against defined rules.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
{{projectName}} validate <files...> [options]
|
|
39
|
+
|
|
40
|
+
Options:
|
|
41
|
+
-c, --config Path to config file
|
|
42
|
+
-f, --fix Auto-fix issues
|
|
43
|
+
--no-cache Disable caching
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
#### `serve`
|
|
47
|
+
Start a development server.
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
{{projectName}} serve [options]
|
|
51
|
+
|
|
52
|
+
Options:
|
|
53
|
+
-p, --port Port to listen on (default: 3000)
|
|
54
|
+
-h, --host Host to bind to (default: localhost)
|
|
55
|
+
--no-open Don't open browser
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### `config`
|
|
59
|
+
Manage configuration settings.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
{{projectName}} config <action> [key] [value]
|
|
63
|
+
|
|
64
|
+
Actions:
|
|
65
|
+
get <key> Get a config value
|
|
66
|
+
set <key> <value> Set a config value
|
|
67
|
+
list List all config values
|
|
68
|
+
reset Reset to defaults
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Global Options
|
|
72
|
+
|
|
73
|
+
- `-v, --version` - Show version
|
|
74
|
+
- `-h, --help` - Show help
|
|
75
|
+
- `--verbose` - Enable verbose output
|
|
76
|
+
- `--quiet` - Suppress output
|
|
77
|
+
- `--no-color` - Disable colored output
|
|
78
|
+
|
|
79
|
+
## Configuration
|
|
80
|
+
|
|
81
|
+
Create a `{{projectName}}.config.js` file in your project root:
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
export default {
|
|
85
|
+
// Configuration options
|
|
86
|
+
rules: {
|
|
87
|
+
// Define your rules
|
|
88
|
+
},
|
|
89
|
+
server: {
|
|
90
|
+
port: 3000,
|
|
91
|
+
host: 'localhost'
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Development
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# Install dependencies
|
|
100
|
+
bun install
|
|
101
|
+
|
|
102
|
+
# Run in development
|
|
103
|
+
bun dev
|
|
104
|
+
|
|
105
|
+
# Run tests
|
|
106
|
+
bun test
|
|
107
|
+
|
|
108
|
+
# Build for production
|
|
109
|
+
bun run build
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
{{license}}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "{{description}}",
|
|
6
|
+
"author": "{{author}}",
|
|
7
|
+
"license": "{{license}}",
|
|
8
|
+
"bin": {
|
|
9
|
+
"{{projectName}}": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"dev": "bun run src/index.ts",
|
|
13
|
+
"build": "bunli build",
|
|
14
|
+
"test": "bun test",
|
|
15
|
+
"test:watch": "bun test --watch",
|
|
16
|
+
"type-check": "tsc --noEmit",
|
|
17
|
+
"lint": "tsc --noEmit",
|
|
18
|
+
"prepare": "bun run build"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@bunli/core": "latest",
|
|
22
|
+
"@bunli/utils": "latest",
|
|
23
|
+
"zod": "^3.22.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@bunli/test": "latest",
|
|
27
|
+
"@types/bun": "latest",
|
|
28
|
+
"bunli": "latest",
|
|
29
|
+
"typescript": "^5.0.0"
|
|
30
|
+
},
|
|
31
|
+
"bunli": {
|
|
32
|
+
"entry": "./src/index.ts",
|
|
33
|
+
"outDir": "./dist",
|
|
34
|
+
"external": ["@bunli/core", "@bunli/utils", "zod"]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { defineCommand, option } from '@bunli/core'
|
|
2
|
+
import { z } from 'zod'
|
|
3
|
+
import { loadConfig, saveConfig, getConfigPath } from '../utils/config.js'
|
|
4
|
+
|
|
5
|
+
export const configCommand = defineCommand({
|
|
6
|
+
name: 'config',
|
|
7
|
+
description: 'Manage configuration',
|
|
8
|
+
subcommands: [
|
|
9
|
+
defineCommand({
|
|
10
|
+
name: 'get',
|
|
11
|
+
description: 'Get a config value',
|
|
12
|
+
args: z.tuple([z.string()]).describe('Config key to get'),
|
|
13
|
+
handler: async ({ args, colors }) => {
|
|
14
|
+
const [key] = args
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
const config = await loadConfig()
|
|
18
|
+
const value = getNestedValue(config, key)
|
|
19
|
+
|
|
20
|
+
if (value === undefined) {
|
|
21
|
+
console.log(colors.yellow(`Config key '${key}' not found`))
|
|
22
|
+
} else {
|
|
23
|
+
console.log(JSON.stringify(value, null, 2))
|
|
24
|
+
}
|
|
25
|
+
} catch (error) {
|
|
26
|
+
console.error(colors.red(`Failed to load config: ${error}`))
|
|
27
|
+
process.exit(1)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}),
|
|
31
|
+
|
|
32
|
+
defineCommand({
|
|
33
|
+
name: 'set',
|
|
34
|
+
description: 'Set a config value',
|
|
35
|
+
args: z.tuple([z.string(), z.string()]).describe('Config key and value'),
|
|
36
|
+
handler: async ({ args, colors, spinner }) => {
|
|
37
|
+
const [key, value] = args
|
|
38
|
+
|
|
39
|
+
const spin = spinner('Updating config...')
|
|
40
|
+
spin.start()
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const config = await loadConfig()
|
|
44
|
+
setNestedValue(config, key, JSON.parse(value))
|
|
45
|
+
await saveConfig(config)
|
|
46
|
+
|
|
47
|
+
spin.succeed(`Config '${key}' updated`)
|
|
48
|
+
} catch (error) {
|
|
49
|
+
spin.fail('Failed to update config')
|
|
50
|
+
console.error(colors.red(String(error)))
|
|
51
|
+
process.exit(1)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}),
|
|
55
|
+
|
|
56
|
+
defineCommand({
|
|
57
|
+
name: 'list',
|
|
58
|
+
description: 'List all config values',
|
|
59
|
+
handler: async ({ colors }) => {
|
|
60
|
+
try {
|
|
61
|
+
const config = await loadConfig()
|
|
62
|
+
const configPath = await getConfigPath()
|
|
63
|
+
|
|
64
|
+
console.log(colors.bold('Configuration:'))
|
|
65
|
+
console.log(colors.dim(` File: ${configPath}`))
|
|
66
|
+
console.log()
|
|
67
|
+
console.log(JSON.stringify(config, null, 2))
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error(colors.red(`Failed to load config: ${error}`))
|
|
70
|
+
process.exit(1)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}),
|
|
74
|
+
|
|
75
|
+
defineCommand({
|
|
76
|
+
name: 'reset',
|
|
77
|
+
description: 'Reset config to defaults',
|
|
78
|
+
options: {
|
|
79
|
+
force: option(
|
|
80
|
+
z.boolean().default(false),
|
|
81
|
+
{
|
|
82
|
+
short: 'f',
|
|
83
|
+
description: 'Skip confirmation'
|
|
84
|
+
}
|
|
85
|
+
)
|
|
86
|
+
},
|
|
87
|
+
handler: async ({ flags, colors, prompt, spinner }) => {
|
|
88
|
+
if (!flags.force) {
|
|
89
|
+
const confirmed = await prompt.confirm(
|
|
90
|
+
'This will reset all config to defaults. Continue?',
|
|
91
|
+
{ default: false }
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
if (!confirmed) {
|
|
95
|
+
console.log(colors.yellow('Reset cancelled'))
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const spin = spinner('Resetting config...')
|
|
101
|
+
spin.start()
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
const { DEFAULT_CONFIG } = await import('../utils/constants.js')
|
|
105
|
+
await saveConfig(DEFAULT_CONFIG)
|
|
106
|
+
|
|
107
|
+
spin.succeed('Config reset to defaults')
|
|
108
|
+
} catch (error) {
|
|
109
|
+
spin.fail('Failed to reset config')
|
|
110
|
+
console.error(colors.red(String(error)))
|
|
111
|
+
process.exit(1)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
]
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
function getNestedValue(obj: any, path: string): any {
|
|
119
|
+
const keys = path.split('.')
|
|
120
|
+
let current = obj
|
|
121
|
+
|
|
122
|
+
for (const key of keys) {
|
|
123
|
+
if (current === null || current === undefined) {
|
|
124
|
+
return undefined
|
|
125
|
+
}
|
|
126
|
+
current = current[key]
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return current
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function setNestedValue(obj: any, path: string, value: any): void {
|
|
133
|
+
const keys = path.split('.')
|
|
134
|
+
const lastKey = keys.pop()!
|
|
135
|
+
let current = obj
|
|
136
|
+
|
|
137
|
+
for (const key of keys) {
|
|
138
|
+
if (!(key in current) || typeof current[key] !== 'object') {
|
|
139
|
+
current[key] = {}
|
|
140
|
+
}
|
|
141
|
+
current = current[key]
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
current[lastKey] = value
|
|
145
|
+
}
|