create-bunli 0.5.5 → 0.6.1
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/dist/cli.js +574 -74
- package/dist/create-project.d.ts +24 -1
- package/dist/create.d.ts +16 -1
- package/dist/index.js +532 -63
- package/dist/templates/advanced/package.json +2 -1
- package/dist/templates/advanced/src/commands/config.ts +152 -70
- package/dist/templates/advanced/src/commands/serve.ts +2 -2
- package/dist/templates/advanced/src/commands/validate.ts +20 -25
- package/dist/templates/advanced/src/index.ts +33 -22
- package/dist/templates/advanced/src/utils/config.ts +5 -4
- package/dist/templates/monorepo/packages/cli/package.json +2 -2
- package/dist/templates/monorepo/packages/core/package.json +1 -1
- package/dist/templates/monorepo/packages/core/src/commands/analyze.ts +9 -4
- package/dist/templates/monorepo/packages/core/src/commands/process.ts +10 -5
- package/package.json +6 -5
- package/templates/advanced/package.json +2 -1
- package/templates/advanced/src/commands/config.ts +152 -70
- package/templates/advanced/src/commands/serve.ts +2 -2
- package/templates/advanced/src/commands/validate.ts +20 -25
- package/templates/advanced/src/index.ts +33 -22
- package/templates/advanced/src/utils/config.ts +5 -4
- package/templates/monorepo/packages/cli/package.json +2 -2
- package/templates/monorepo/packages/core/package.json +1 -1
- package/templates/monorepo/packages/core/src/commands/analyze.ts +9 -4
- package/templates/monorepo/packages/core/src/commands/process.ts +10 -5
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@bunli/core": "latest",
|
|
23
23
|
"@bunli/utils": "latest",
|
|
24
|
+
"better-result": "^2.7.0",
|
|
24
25
|
"zod": "^3.22.0"
|
|
25
26
|
},
|
|
26
27
|
"devDependencies": {
|
|
@@ -34,4 +35,4 @@
|
|
|
34
35
|
"outDir": "./dist",
|
|
35
36
|
"external": ["@bunli/core", "@bunli/utils", "zod"]
|
|
36
37
|
}
|
|
37
|
-
}
|
|
38
|
+
}
|
|
@@ -1,77 +1,150 @@
|
|
|
1
1
|
import { defineCommand, option } from '@bunli/core'
|
|
2
|
+
import { Result, TaggedError } from 'better-result'
|
|
2
3
|
import { z } from 'zod'
|
|
3
4
|
import { loadConfig, saveConfig, getConfigPath } from '../utils/config.js'
|
|
5
|
+
import { DEFAULT_CONFIG } from '../utils/constants.js'
|
|
6
|
+
|
|
7
|
+
const toErrorMessage = (error: unknown): string =>
|
|
8
|
+
error instanceof Error ? error.message : String(error)
|
|
9
|
+
|
|
10
|
+
class ConfigCommandError extends TaggedError('ConfigCommandError')<{
|
|
11
|
+
message: string
|
|
12
|
+
cause?: unknown
|
|
13
|
+
}>() {
|
|
14
|
+
constructor(message: string, cause?: unknown) {
|
|
15
|
+
super(cause === undefined ? { message } : { message, cause })
|
|
16
|
+
}
|
|
17
|
+
}
|
|
4
18
|
|
|
5
19
|
const configCommand = defineCommand({
|
|
6
20
|
name: 'config',
|
|
7
21
|
description: 'Manage configuration',
|
|
8
|
-
|
|
22
|
+
commands: [
|
|
9
23
|
defineCommand({
|
|
10
24
|
name: 'get',
|
|
11
25
|
description: 'Get a config value',
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
console.error(colors.red(
|
|
27
|
-
process.
|
|
26
|
+
handler: async ({ positional, colors }) => {
|
|
27
|
+
const key = positional[0]
|
|
28
|
+
if (!key) {
|
|
29
|
+
console.error(colors.red('Usage: config get <key>'))
|
|
30
|
+
process.exitCode = 1
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const configResult = await Result.tryPromise({
|
|
35
|
+
try: () => loadConfig(),
|
|
36
|
+
catch: (cause) => new ConfigCommandError(`Failed to load config: ${toErrorMessage(cause)}`, cause)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
if (Result.isError(configResult)) {
|
|
40
|
+
console.error(colors.red(configResult.error.message))
|
|
41
|
+
process.exitCode = 1
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const value = getNestedValue(configResult.value as Record<string, unknown>, key)
|
|
46
|
+
|
|
47
|
+
if (value === undefined) {
|
|
48
|
+
console.log(colors.yellow(`Config key '${key}' not found`))
|
|
49
|
+
} else {
|
|
50
|
+
console.log(JSON.stringify(value, null, 2))
|
|
28
51
|
}
|
|
29
52
|
}
|
|
30
53
|
}),
|
|
31
|
-
|
|
54
|
+
|
|
32
55
|
defineCommand({
|
|
33
56
|
name: 'set',
|
|
34
57
|
description: 'Set a config value',
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
58
|
+
handler: async ({ positional, colors, spinner }) => {
|
|
59
|
+
const key = positional[0]
|
|
60
|
+
const rawValue = positional[1]
|
|
61
|
+
|
|
62
|
+
if (!key || rawValue === undefined) {
|
|
63
|
+
console.error(colors.red('Usage: config set <key> <json-value>'))
|
|
64
|
+
process.exitCode = 1
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
39
68
|
const spin = spinner('Updating config...')
|
|
40
69
|
spin.start()
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
70
|
+
|
|
71
|
+
const configResult = await Result.tryPromise({
|
|
72
|
+
try: () => loadConfig(),
|
|
73
|
+
catch: (cause) => new ConfigCommandError(`Failed to load config: ${toErrorMessage(cause)}`, cause)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
if (Result.isError(configResult)) {
|
|
77
|
+
spin.fail('Failed to update config')
|
|
78
|
+
console.error(colors.red(configResult.error.message))
|
|
79
|
+
process.exitCode = 1
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const parsedValue = Result.try({
|
|
84
|
+
try: () => JSON.parse(rawValue),
|
|
85
|
+
catch: (cause) =>
|
|
86
|
+
new ConfigCommandError(`Failed to parse value as JSON: ${toErrorMessage(cause)}`, cause)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
if (Result.isError(parsedValue)) {
|
|
90
|
+
spin.fail('Failed to update config')
|
|
91
|
+
console.error(colors.red(parsedValue.error.message))
|
|
92
|
+
process.exitCode = 1
|
|
93
|
+
return
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const nextConfig = configResult.value as Record<string, unknown>
|
|
97
|
+
setNestedValue(nextConfig, key, parsedValue.value)
|
|
98
|
+
|
|
99
|
+
const saveResult = await Result.tryPromise({
|
|
100
|
+
try: () => saveConfig(nextConfig),
|
|
101
|
+
catch: (cause) => new ConfigCommandError(`Failed to save config: ${toErrorMessage(cause)}`, cause)
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
if (Result.isError(saveResult)) {
|
|
49
105
|
spin.fail('Failed to update config')
|
|
50
|
-
console.error(colors.red(
|
|
51
|
-
process.
|
|
106
|
+
console.error(colors.red(saveResult.error.message))
|
|
107
|
+
process.exitCode = 1
|
|
108
|
+
return
|
|
52
109
|
}
|
|
110
|
+
|
|
111
|
+
spin.succeed(`Config '${key}' updated`)
|
|
53
112
|
}
|
|
54
113
|
}),
|
|
55
|
-
|
|
114
|
+
|
|
56
115
|
defineCommand({
|
|
57
116
|
name: 'list',
|
|
58
117
|
description: 'List all config values',
|
|
59
118
|
handler: async ({ colors }) => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
console.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
console.error(colors.red(`Failed to load config: ${error}`))
|
|
70
|
-
process.exit(1)
|
|
119
|
+
const configResult = await Result.tryPromise({
|
|
120
|
+
try: () => loadConfig(),
|
|
121
|
+
catch: (cause) => new ConfigCommandError(`Failed to load config: ${toErrorMessage(cause)}`, cause)
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
if (Result.isError(configResult)) {
|
|
125
|
+
console.error(colors.red(configResult.error.message))
|
|
126
|
+
process.exitCode = 1
|
|
127
|
+
return
|
|
71
128
|
}
|
|
129
|
+
|
|
130
|
+
const configPathResult = await Result.tryPromise({
|
|
131
|
+
try: () => getConfigPath(),
|
|
132
|
+
catch: (cause) => new ConfigCommandError(`Failed to resolve config path: ${toErrorMessage(cause)}`, cause)
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
if (Result.isError(configPathResult)) {
|
|
136
|
+
console.error(colors.red(configPathResult.error.message))
|
|
137
|
+
process.exitCode = 1
|
|
138
|
+
return
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
console.log(colors.bold('Configuration:'))
|
|
142
|
+
console.log(colors.dim(` File: ${configPathResult.value}`))
|
|
143
|
+
console.log()
|
|
144
|
+
console.log(JSON.stringify(configResult.value, null, 2))
|
|
72
145
|
}
|
|
73
146
|
}),
|
|
74
|
-
|
|
147
|
+
|
|
75
148
|
defineCommand({
|
|
76
149
|
name: 'reset',
|
|
77
150
|
description: 'Reset config to defaults',
|
|
@@ -90,58 +163,67 @@ const configCommand = defineCommand({
|
|
|
90
163
|
'This will reset all config to defaults. Continue?',
|
|
91
164
|
{ default: false }
|
|
92
165
|
)
|
|
93
|
-
|
|
166
|
+
|
|
94
167
|
if (!confirmed) {
|
|
95
168
|
console.log(colors.yellow('Reset cancelled'))
|
|
96
169
|
return
|
|
97
170
|
}
|
|
98
171
|
}
|
|
99
|
-
|
|
172
|
+
|
|
100
173
|
const spin = spinner('Resetting config...')
|
|
101
174
|
spin.start()
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
175
|
+
|
|
176
|
+
const saveResult = await Result.tryPromise({
|
|
177
|
+
try: () => saveConfig(DEFAULT_CONFIG),
|
|
178
|
+
catch: (cause) => new ConfigCommandError(`Failed to save config: ${toErrorMessage(cause)}`, cause)
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
if (Result.isError(saveResult)) {
|
|
109
182
|
spin.fail('Failed to reset config')
|
|
110
|
-
console.error(colors.red(
|
|
111
|
-
process.
|
|
183
|
+
console.error(colors.red(saveResult.error.message))
|
|
184
|
+
process.exitCode = 1
|
|
185
|
+
return
|
|
112
186
|
}
|
|
187
|
+
|
|
188
|
+
spin.succeed('Config reset to defaults')
|
|
113
189
|
}
|
|
114
190
|
})
|
|
115
191
|
]
|
|
116
192
|
})
|
|
117
193
|
|
|
118
|
-
function getNestedValue(obj:
|
|
194
|
+
function getNestedValue(obj: Record<string, unknown>, path: string): unknown {
|
|
119
195
|
const keys = path.split('.')
|
|
120
|
-
let current = obj
|
|
121
|
-
|
|
196
|
+
let current: unknown = obj
|
|
197
|
+
|
|
122
198
|
for (const key of keys) {
|
|
123
|
-
if (current
|
|
199
|
+
if (!current || typeof current !== 'object') {
|
|
124
200
|
return undefined
|
|
125
201
|
}
|
|
126
|
-
|
|
202
|
+
|
|
203
|
+
current = (current as Record<string, unknown>)[key]
|
|
127
204
|
}
|
|
128
|
-
|
|
205
|
+
|
|
129
206
|
return current
|
|
130
207
|
}
|
|
131
208
|
|
|
132
|
-
function setNestedValue(obj:
|
|
209
|
+
function setNestedValue(obj: Record<string, unknown>, path: string, value: unknown): void {
|
|
133
210
|
const keys = path.split('.')
|
|
134
|
-
const lastKey = keys.pop()
|
|
135
|
-
|
|
136
|
-
|
|
211
|
+
const lastKey = keys.pop()
|
|
212
|
+
if (!lastKey) {
|
|
213
|
+
return
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
let current: Record<string, unknown> = obj
|
|
217
|
+
|
|
137
218
|
for (const key of keys) {
|
|
138
|
-
|
|
219
|
+
const next = current[key]
|
|
220
|
+
if (!next || typeof next !== 'object' || Array.isArray(next)) {
|
|
139
221
|
current[key] = {}
|
|
140
222
|
}
|
|
141
|
-
current = current[key]
|
|
223
|
+
current = current[key] as Record<string, unknown>
|
|
142
224
|
}
|
|
143
|
-
|
|
225
|
+
|
|
144
226
|
current[lastKey] = value
|
|
145
227
|
}
|
|
146
228
|
|
|
147
|
-
export default configCommand
|
|
229
|
+
export default configCommand
|
|
@@ -7,7 +7,7 @@ const serveCommand = defineCommand({
|
|
|
7
7
|
description: 'Start a development server',
|
|
8
8
|
options: {
|
|
9
9
|
port: option(
|
|
10
|
-
z.number().int().min(1).max(65535).default(3000),
|
|
10
|
+
z.coerce.number().int().min(1).max(65535).default(3000),
|
|
11
11
|
{
|
|
12
12
|
short: 'p',
|
|
13
13
|
description: 'Port to listen on'
|
|
@@ -175,4 +175,4 @@ function getHomePage(): string {
|
|
|
175
175
|
`.trim()
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
-
export default serveCommand
|
|
178
|
+
export default serveCommand
|
|
@@ -7,7 +7,6 @@ import { glob } from '../utils/glob.js'
|
|
|
7
7
|
const validateCommand = defineCommand({
|
|
8
8
|
name: 'validate',
|
|
9
9
|
description: 'Validate files against defined rules',
|
|
10
|
-
args: z.array(z.string()).min(1).describe('Files to validate'),
|
|
11
10
|
options: {
|
|
12
11
|
config: option(
|
|
13
12
|
z.string().optional(),
|
|
@@ -30,66 +29,63 @@ const validateCommand = defineCommand({
|
|
|
30
29
|
}
|
|
31
30
|
)
|
|
32
31
|
},
|
|
33
|
-
handler: async ({
|
|
32
|
+
handler: async ({ positional, flags, colors, spinner }) => {
|
|
34
33
|
const spin = spinner('Loading configuration...')
|
|
35
34
|
spin.start()
|
|
36
|
-
|
|
35
|
+
|
|
37
36
|
try {
|
|
38
|
-
// Load config
|
|
39
37
|
const config = await loadConfig(flags.config)
|
|
40
38
|
spin.succeed('Configuration loaded')
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
|
|
40
|
+
const patterns = positional.length > 0 ? positional : config.include || ['src/**/*.{js,ts}']
|
|
41
|
+
|
|
43
42
|
const fileSpin = spinner('Resolving files...')
|
|
44
43
|
fileSpin.start()
|
|
45
|
-
|
|
46
|
-
const files = await glob(
|
|
44
|
+
|
|
45
|
+
const files = await glob(patterns, {
|
|
47
46
|
include: config.include,
|
|
48
47
|
exclude: config.exclude
|
|
49
48
|
})
|
|
50
|
-
|
|
49
|
+
|
|
51
50
|
fileSpin.succeed(`Found ${files.length} files to validate`)
|
|
52
|
-
|
|
51
|
+
|
|
53
52
|
if (files.length === 0) {
|
|
54
53
|
console.log(colors.yellow('No files matched the pattern'))
|
|
55
54
|
return
|
|
56
55
|
}
|
|
57
|
-
|
|
58
|
-
// Run validation
|
|
56
|
+
|
|
59
57
|
const validateSpin = spinner('Validating files...')
|
|
60
58
|
validateSpin.start()
|
|
61
|
-
|
|
59
|
+
|
|
62
60
|
const results = await validateFiles(files, {
|
|
63
61
|
rules: config.rules,
|
|
64
62
|
fix: flags.fix,
|
|
65
63
|
cache: flags.cache && config.cache?.enabled
|
|
66
64
|
})
|
|
67
|
-
|
|
65
|
+
|
|
68
66
|
validateSpin.stop()
|
|
69
|
-
|
|
70
|
-
// Display results
|
|
67
|
+
|
|
71
68
|
let hasErrors = false
|
|
72
|
-
|
|
69
|
+
|
|
73
70
|
for (const result of results) {
|
|
74
71
|
if (result.errors.length > 0 || result.warnings.length > 0) {
|
|
75
72
|
console.log()
|
|
76
73
|
console.log(colors.bold(result.file))
|
|
77
|
-
|
|
74
|
+
|
|
78
75
|
for (const error of result.errors) {
|
|
79
76
|
console.log(colors.red(` ✗ ${error.line}:${error.column} ${error.message}`))
|
|
80
77
|
hasErrors = true
|
|
81
78
|
}
|
|
82
|
-
|
|
79
|
+
|
|
83
80
|
for (const warning of result.warnings) {
|
|
84
81
|
console.log(colors.yellow(` ⚠ ${warning.line}:${warning.column} ${warning.message}`))
|
|
85
82
|
}
|
|
86
83
|
}
|
|
87
84
|
}
|
|
88
|
-
|
|
89
|
-
// Summary
|
|
85
|
+
|
|
90
86
|
const totalErrors = results.reduce((sum, r) => sum + r.errors.length, 0)
|
|
91
87
|
const totalWarnings = results.reduce((sum, r) => sum + r.warnings.length, 0)
|
|
92
|
-
|
|
88
|
+
|
|
93
89
|
console.log()
|
|
94
90
|
if (totalErrors === 0 && totalWarnings === 0) {
|
|
95
91
|
console.log(colors.green('✅ All files passed validation!'))
|
|
@@ -101,12 +97,11 @@ const validateCommand = defineCommand({
|
|
|
101
97
|
if (totalWarnings > 0) {
|
|
102
98
|
console.log(colors.yellow(` ${totalWarnings} warning${totalWarnings !== 1 ? 's' : ''}`))
|
|
103
99
|
}
|
|
104
|
-
|
|
100
|
+
|
|
105
101
|
if (hasErrors) {
|
|
106
102
|
process.exit(1)
|
|
107
103
|
}
|
|
108
104
|
}
|
|
109
|
-
|
|
110
105
|
} catch (error) {
|
|
111
106
|
spin.fail('Validation failed')
|
|
112
107
|
console.error(colors.red(String(error)))
|
|
@@ -115,4 +110,4 @@ const validateCommand = defineCommand({
|
|
|
115
110
|
}
|
|
116
111
|
})
|
|
117
112
|
|
|
118
|
-
export default validateCommand
|
|
113
|
+
export default validateCommand
|
|
@@ -1,44 +1,55 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { createCLI } from '@bunli/core'
|
|
3
|
+
import { Result, TaggedError } from 'better-result'
|
|
3
4
|
import initCommand from './commands/init.js'
|
|
4
5
|
import validateCommand from './commands/validate.js'
|
|
5
6
|
import serveCommand from './commands/serve.js'
|
|
6
7
|
import configCommand from './commands/config.js'
|
|
7
8
|
import { loadConfig } from './utils/config.js'
|
|
8
9
|
|
|
10
|
+
const toErrorMessage = (error: unknown): string =>
|
|
11
|
+
error instanceof Error ? error.message : String(error)
|
|
12
|
+
|
|
13
|
+
class CliStartupError extends TaggedError('CliStartupError')<{
|
|
14
|
+
message: string
|
|
15
|
+
cause: unknown
|
|
16
|
+
}>() {
|
|
17
|
+
constructor(cause: unknown) {
|
|
18
|
+
super({ message: `Failed to start CLI: ${toErrorMessage(cause)}`, cause })
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
9
22
|
const cli = await createCLI({
|
|
10
23
|
name: '{{name}}',
|
|
11
24
|
version: '0.1.0',
|
|
12
25
|
description: '{{description}}'
|
|
13
26
|
})
|
|
14
27
|
|
|
15
|
-
// Global options
|
|
16
|
-
cli.option('verbose', {
|
|
17
|
-
type: 'boolean',
|
|
18
|
-
description: 'Enable verbose output'
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
cli.option('quiet', {
|
|
22
|
-
type: 'boolean',
|
|
23
|
-
description: 'Suppress output'
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
// Add commands
|
|
27
28
|
cli.command(initCommand)
|
|
28
29
|
cli.command(validateCommand)
|
|
29
30
|
cli.command(serveCommand)
|
|
30
31
|
cli.command(configCommand)
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
process.exit(1)
|
|
33
|
+
async function run(): Promise<Result<void, CliStartupError>> {
|
|
34
|
+
const configResult = await Result.tryPromise({
|
|
35
|
+
try: () => loadConfig(),
|
|
36
|
+
catch: (cause) => new CliStartupError(cause)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
if (Result.isError(configResult)) {
|
|
40
|
+
return configResult
|
|
41
41
|
}
|
|
42
|
+
|
|
43
|
+
return Result.tryPromise({
|
|
44
|
+
try: async () => {
|
|
45
|
+
await cli.run()
|
|
46
|
+
},
|
|
47
|
+
catch: (cause) => new CliStartupError(cause)
|
|
48
|
+
})
|
|
42
49
|
}
|
|
43
50
|
|
|
44
|
-
await run()
|
|
51
|
+
const result = await run()
|
|
52
|
+
if (Result.isError(result)) {
|
|
53
|
+
console.error(result.error.message)
|
|
54
|
+
process.exit(1)
|
|
55
|
+
}
|
|
@@ -43,7 +43,7 @@ export async function loadConfig(configPath?: string): Promise<Config> {
|
|
|
43
43
|
const config = configModule.default || configModule
|
|
44
44
|
|
|
45
45
|
// Merge with defaults
|
|
46
|
-
|
|
46
|
+
const mergedConfig: Config = {
|
|
47
47
|
...DEFAULT_CONFIG,
|
|
48
48
|
...config,
|
|
49
49
|
server: {
|
|
@@ -51,8 +51,9 @@ export async function loadConfig(configPath?: string): Promise<Config> {
|
|
|
51
51
|
...(config.server || {})
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
|
|
55
|
+
cachedConfig = mergedConfig
|
|
56
|
+
return mergedConfig
|
|
56
57
|
} catch (error) {
|
|
57
58
|
console.warn(`Failed to load config from ${finalPath}:`, error)
|
|
58
59
|
return DEFAULT_CONFIG
|
|
@@ -80,4 +81,4 @@ export async function getConfigPath(): Promise<string> {
|
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
return 'No config file found'
|
|
83
|
-
}
|
|
84
|
+
}
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@bunli/core": "latest",
|
|
21
|
-
"@{{name}}/core": "workspace
|
|
22
|
-
"@{{name}}/utils": "workspace
|
|
21
|
+
"@{{name}}/core": "workspace:^",
|
|
22
|
+
"@{{name}}/utils": "workspace:^"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@bunli/test": "latest",
|
|
@@ -6,7 +6,6 @@ import type { AnalyzeResult } from '../types.js'
|
|
|
6
6
|
const analyzeCommand = defineCommand({
|
|
7
7
|
name: 'analyze',
|
|
8
8
|
description: 'Analyze files and generate reports',
|
|
9
|
-
args: z.array(z.string()).min(1).describe('Files to analyze'),
|
|
10
9
|
options: {
|
|
11
10
|
detailed: option(
|
|
12
11
|
z.boolean().default(false),
|
|
@@ -16,12 +15,18 @@ const analyzeCommand = defineCommand({
|
|
|
16
15
|
}
|
|
17
16
|
)
|
|
18
17
|
},
|
|
19
|
-
handler: async ({
|
|
18
|
+
handler: async ({ positional, flags, colors }) => {
|
|
19
|
+
const files = positional
|
|
20
|
+
if (files.length === 0) {
|
|
21
|
+
logger.error('Usage: analyze <file...>')
|
|
22
|
+
process.exit(1)
|
|
23
|
+
}
|
|
24
|
+
|
|
20
25
|
logger.info('Starting analysis...')
|
|
21
26
|
|
|
22
27
|
const results: AnalyzeResult[] = []
|
|
23
28
|
|
|
24
|
-
for (const file of
|
|
29
|
+
for (const file of files) {
|
|
25
30
|
try {
|
|
26
31
|
const result = await analyzeFile(file)
|
|
27
32
|
results.push(result)
|
|
@@ -83,4 +88,4 @@ async function analyzeFile(file: string): Promise<AnalyzeResult> {
|
|
|
83
88
|
}
|
|
84
89
|
}
|
|
85
90
|
|
|
86
|
-
export default analyzeCommand
|
|
91
|
+
export default analyzeCommand
|
|
@@ -6,7 +6,6 @@ import type { ProcessOptions } from '../types.js'
|
|
|
6
6
|
const processCommand = defineCommand({
|
|
7
7
|
name: 'process',
|
|
8
8
|
description: 'Process input files',
|
|
9
|
-
args: z.array(z.string()).min(1).describe('Files to process'),
|
|
10
9
|
options: {
|
|
11
10
|
output: option(
|
|
12
11
|
z.string().optional(),
|
|
@@ -30,12 +29,18 @@ const processCommand = defineCommand({
|
|
|
30
29
|
}
|
|
31
30
|
)
|
|
32
31
|
},
|
|
33
|
-
handler: async ({
|
|
32
|
+
handler: async ({ positional, flags, spinner }) => {
|
|
33
|
+
const files = positional
|
|
34
|
+
if (files.length === 0) {
|
|
35
|
+
logger.error('Usage: process <file...>')
|
|
36
|
+
process.exit(1)
|
|
37
|
+
}
|
|
38
|
+
|
|
34
39
|
const spin = spinner('Processing files...')
|
|
35
40
|
spin.start()
|
|
36
41
|
|
|
37
42
|
try {
|
|
38
|
-
for (const file of
|
|
43
|
+
for (const file of files) {
|
|
39
44
|
if (flags.verbose) {
|
|
40
45
|
logger.info(`Processing ${file}`)
|
|
41
46
|
}
|
|
@@ -49,7 +54,7 @@ const processCommand = defineCommand({
|
|
|
49
54
|
})
|
|
50
55
|
}
|
|
51
56
|
|
|
52
|
-
spin.succeed(`Processed ${
|
|
57
|
+
spin.succeed(`Processed ${files.length} files`)
|
|
53
58
|
} catch (error) {
|
|
54
59
|
spin.fail('Processing failed')
|
|
55
60
|
logger.error(error)
|
|
@@ -63,4 +68,4 @@ async function processFile(file: string, options: ProcessOptions): Promise<void>
|
|
|
63
68
|
logger.debug(`Processing ${file} with options:`, options)
|
|
64
69
|
}
|
|
65
70
|
|
|
66
|
-
export default processCommand
|
|
71
|
+
export default processCommand
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-bunli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Scaffold new Bunli CLI projects",
|
|
6
6
|
"bin": {
|
|
@@ -47,14 +47,15 @@
|
|
|
47
47
|
"prepublishOnly": "bun run build"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@bunli/core": "0.
|
|
51
|
-
"@bunli/test": "0.
|
|
52
|
-
"@bunli/utils": "0.
|
|
50
|
+
"@bunli/core": "^0.6.1",
|
|
51
|
+
"@bunli/test": "^0.4.1",
|
|
52
|
+
"@bunli/utils": "^0.4.0",
|
|
53
|
+
"better-result": "^2.7.0",
|
|
53
54
|
"giget": "^2.0.0",
|
|
54
55
|
"zod": "^4.3.6"
|
|
55
56
|
},
|
|
56
57
|
"devDependencies": {
|
|
57
|
-
"@types/bun": "1.3.
|
|
58
|
+
"@types/bun": "1.3.9",
|
|
58
59
|
"typescript": "^5.8.3"
|
|
59
60
|
}
|
|
60
61
|
}
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@bunli/core": "latest",
|
|
23
23
|
"@bunli/utils": "latest",
|
|
24
|
+
"better-result": "^2.7.0",
|
|
24
25
|
"zod": "^3.22.0"
|
|
25
26
|
},
|
|
26
27
|
"devDependencies": {
|
|
@@ -34,4 +35,4 @@
|
|
|
34
35
|
"outDir": "./dist",
|
|
35
36
|
"external": ["@bunli/core", "@bunli/utils", "zod"]
|
|
36
37
|
}
|
|
37
|
-
}
|
|
38
|
+
}
|